📜 ⬆️ ⬇️

Making a kaleidoscope on CSS + JS

image I somehow never thought about such a thing as a kaleidoscope on the page. Saw them somehow earlier, but did not pay special attention. And then I saw in Lebedev’s portfolio a kaleidoscope on a flash, I twisted it with my mouse, I understood the principle of work and thought “Christmas trees, it's not difficult!”.

Of course, one cannot say that it is really very simple. And you can not say that it turned out all that I wanted. But there is something to see, for which I invite under the cat.

UPD
In the post he added an improved version of the hablo man hlomzik , which does not work in IE, but with a smaller amount of code and with more correct behavior.
')

At the very beginning, I hoped that it would work absolutely everywhere and well. It didn't quite work out. As a result:


Immediately I will give a link to the working example, so that it is clear what it is all about: kaleidoscope.terion.name
So let's go.

Task 1: understand how to do it at all.


The kaleidoscope consists of 12 sectors assembled into a disk. Accordingly, the question arises: how to make a sector? Actually, it is very simple. We need 4 blocks and some CSS. It should look like this:
image
The block-container, one block turned by -15 °, inside the block turned by 30 °, inside another turned by -15 °.
The sector has a background image that we will shift.

Task 2: in fact, collect it all.


The code is accordingly very simple:
<div class = "sc s1" >
<div class = "rl" >
<div class = "rr" >
<div class = "sv" >
</div>
</div>
</div>
</div>


Yes, we immediately assume that there may be several kaleidoscopes on the page, so we only use classes.
An important condition : the size of the kaleidoscope should be changed by changing the size of the container only; accordingly, everything inside should be in percent.
Immediately, I note that the percentage values ​​were selected by the method of scientific spearcasting, since my knowledge of trigonometry is not so deep as to calculate all this :)

  1. .scope_container .sc {
  2. width: 50%;
  3. height: 50%;
  4. -webkit-transform-origin: top center;
  5. -moz-transform-origin: top center;
  6. -o-transform-origin: top center;
  7. transform-origin: top center;
  8. position: absolute;
  9. top: 50%;
  10. left: 25%;
  11. z-index: -1;
  12. }
  13. .scope_container .sc div {
  14. overflow: hidden}
  15. .scope_container .rl {
  16. height: 110%;
  17. width: 60%;
  18. -webkit-transform: rotate (-15deg);
  19. -moz-transform: rotate (-15deg);
  20. -o-transform: rotate (-15deg);
  21. transform: rotate (-15deg);
  22. position: relative;
  23. top: 1.5%;
  24. left: 4.5%;
  25. }
  26. .scope_container .rr {
  27. height: 100%;
  28. width: 100%;
  29. -webkit-transform: rotate (30deg);
  30. -moz-transform: rotate (30deg);
  31. -o-transform: rotate (30deg);
  32. transform: rotate (30deg);
  33. position: relative;
  34. top: 7%;
  35. left: 51%;
  36. }
  37. .scope_container .sv {
  38. width: 105%;
  39. height: 105%;
  40. -webkit-transform: rotate (-15deg);
  41. -moz-transform: rotate (-15deg);
  42. -o-transform: rotate (-15deg);
  43. transform: rotate (-15deg);
  44. position: relative;
  45. top: -2%;
  46. left: -29%;
  47. }


So, we have code for the sector. Now these sectors should be 12 and should not be wrapped in 2 containers, because internal is used to position the elements, and external - to set the size and trim unnecessary.

As a result, the entire html-code will be:

  1. < div class = "parent" >
  2. < div class = "scope_container pattern" >
  3. < div class = "sc s1" > < div class = "rl" > < div class = "rr" > < div class = "sv" > </ div > </ div > </ div > </ div >
  4. < div class = "sc s2" > < div class = "rl" > < div class = "rr" > < div class = "sv" > </ div > </ div > </ div > </ div >
  5. < div class = "sc s3" > < div class = "rl" > < div class = "rr" > < div class = "sv" > </ div > </ div > </ div > </ div >
  6. < div class = "sc s4" > < div class = "rl" > < div class = "rr" > < div class = "sv" > </ div > </ div > </ div > </ div >
  7. < div class = "sc s5" > < div class = "rl" > < div class = "rr" > < div class = "sv" > </ div > </ div > </ div > </ div >
  8. < div class = "sc s6" > < div class = "rl" > < div class = "rr" > < div class = "sv" > </ div > </ div > </ div > </ div >
  9. < div class = "sc s7" > < div class = "rl" > < div class = "rr" > < div class = "sv" > </ div > </ div > </ div > </ div >
  10. < div class = "sc s8" > < div class = "rl" > < div class = "rr" > < div class = "sv" > </ div > </ div > </ div > </ div >
  11. < div class = "sc s9" > < div class = "rl" > < div class = "rr" > < div class = "sv" > </ div > </ div > </ div > </ div >
  12. < div class = "sc s10" > < div class = "rl" > < div class = "rr" > < div class = "sv" > </ div > </ div > </ div > </ div >
  13. < div class = "sc s11" > < div class = "rl" > < div class = "rr" > < div class = "sv" > </ div > </ div > </ div > </ div >
  14. < div class = "sc s12" > < div class = "rl" > < div class = "rr" > < div class = "sv" > </ div > </ div > </ div > </ div >
  15. </ div >
  16. </ div >


Classes s1 - s12 to determine the position of each sector.
The pattern class defines which picture will be used (thanks to eto_moy_nick for the pattern :))

Arrange the blocks in places:
  1. .scope_container .s1 {
  2. -webkit-transform: rotate (0deg);
  3. -moz-transform: rotate (0deg);
  4. -o-transform: rotate (0deg);
  5. transform: rotate (0deg);
  6. }
  7. .scope_container .s2 {
  8. -webkit-transform: rotate (30deg);
  9. -moz-transform: rotate (30deg);
  10. -o-transform: rotate (30deg);
  11. transform: rotate (30deg);
  12. }
And so on until the 12th in steps of 30 degrees.

In general, that's all.
But there is an IE who does not understand all this! But for IE there are filters : filter: progid: DXImageTransform. Microsoft. Matrix (...) .
Therefore, in the conditional comment [if IE 8] we add the following code:

  1. .scope_container .s1 {
  2. -webkit-transform: rotate (0deg);
  3. -moz-transform: rotate (0deg);
  4. -o-transform: rotate (0deg);
  5. transform: rotate (0deg);
  6. }
  7. .scope_container .s2 {
  8. -webkit-transform: rotate (30deg);
  9. -moz-transform: rotate (30deg);
  10. -o-transform: rotate (30deg);
  11. transform: rotate (30deg);
  12. }
As shown by experiments, with absolute positioning and the matrix at the IE trouble. Therefore it was necessary to fence such crutches.

Further:
  1. .s2 {
  2. filter: progid: DXImageTransform.Microsoft.Matrix (M11 = 0.86602540, M12 = -0.50000000, M21 = 0.50000000, M22 = 0.86602540, SizingMethod = 'auto expand', FilterType = 'nearest neighbor');
  3. margin: -64.5% 0 0 -25%;
  4. }
  5. .s3 {
  6. filter: progid: DXImageTransform.Microsoft.Matrix (M11 = 0.50000000, M12 = -0.86602540, M21 = 0.86602540, M22 = 0.50000000, SizingMethod = 'auto expand', FilterType = 'nearest neighbor');
  7. margin: -60.5% 0 0 -32.8%;
  8. }
Etc.
To my surprise, FilterType = 'nearest neighbor' did not work (without bicubic anti-aliasing, most likely there would be no such brakes).
For matrix calculations, I used this tool that just saved my life: www.boogdesign.com/examples/transforms/matrix-calculator.html
Margins were manually placed blocks. If there is a desire to make this all work in IE7, it is only necessary for him to rewrite these same margins.

Task 3: make it move


Javascript. You need to move the background of the sectors for the mouse. At the same time, we remember that the kaleidoscope on the page is not one. The code below, read the comments:
  1. <script type = "text / javascript" >
  2. // We use classes, but IE does not know how to choose them. We compensate for this disadvantage.
  3. if ( document .getElementsByClassName) {
  4. getElementsByClass = function (classList, node) {
  5. return (node ​​|| document ) .getElementsByClassName (classList)
  6. }
  7. } else {
  8. getElementsByClass = function (classList, node) {
  9. var node = node || document ,
  10. list = node.getElementsByTagName ( '*' ),
  11. length = list.length,
  12. classArray = classList.split (/ \ s + /),
  13. classes = classArray.length,
  14. result = [], i, j
  15. for (i = 0; i <length; i ++) {
  16. for (j = 0; j <classes; j ++) {
  17. if (list [i] .className.search ( '\\ b' + classArray [j] + '\\ b' )! = -1) {
  18. result.push (list [i])
  19. break
  20. }
  21. }
  22. }
  23. return result
  24. }
  25. }
  26. // Get the mouse coordinates
  27. function mousePageXY (e)
  28. {
  29. var x = 0, y = 0;
  30. if (! e) e = window. event ;
  31. if (e.pageX || e.pageY)
  32. {
  33. x = e.pageX;
  34. y = e.pageY;
  35. }
  36. else if (e.clientX || e.clientY)
  37. {
  38. x = e.clientX + ( document .documentElement.scrollLeft || document .body.scrollLeft) - document .documentElement.clientLeft;
  39. y = e.clientY + ( document .documentElement.scrollTop || document .body.scrollTop) - document .documentElement.clientTop;
  40. }
  41. return { "x" : x, "y" : y};
  42. }
  43. window.onload = function () {
  44. var scope_cont = getElementsByClass ( 'scope_container' , document );
  45. // There can be several kaleidoscopes, consider this.
  46. for (i = 0; i <scope_cont.length; i ++)
  47. {
  48. scope_cont [i] .onmouseover = function () {
  49. var sect = getElementsByClass ( 'sv' , this );
  50. var curscope = this ;
  51. this .onmousemove = function (e) {
  52. var mCur = mousePageXY (e);
  53. for (n = 0; n <sect.length; n ++)
  54. {
  55. // In even sectors, the background moves in one direction
  56. if (n% 2) {
  57. sect [n] .style.backgroundPosition = mCur.x + 'px' + mCur.y + 'px' ;
  58. }
  59. // Odd - to another
  60. else {
  61. sect [n] .style.backgroundPosition = mCur.x * (- 1) + 'px' + mCur.y + 'px'
  62. }
  63. }
  64. }
  65. }
  66. scope_cont [i] .onmouseout = function () {
  67. // We clean up after ourselves, so as not to overload the browser
  68. document .onmousemove = null ;
  69. }
  70. }
  71. }
  72. </ script>


In general, it is ready.
Opera:
If the block .pattern add overflow: hidden - ALL disappears. As a result, a blank page with scrolls into emptiness for the width of the "fan".
If overflow: hidden is removed, then in the “fastest browser on earth” © this construction is slower than in IE.
This is a complete failure.

I hope you were interested :)

UPD
And here is an improved version of the hablomelochka hlomzik :
quaint.su/for/habrahabr/kaleidoscope
The discussion in which it was born is: habrahabr.ru/blogs/css/99019/?reply_to=3057019#comment_3054307

Source: https://habr.com/ru/post/99019/


All Articles