13 июля 2010 в 19:50

Делаем калейдоскоп на CSS+JS

CSS*
imageЯ как-то раньше никогда не задумывался над такой штукой, как калейдоскоп на странице. Видел их как-то раньше, но не обращал особо внимания. А тут увидел у Лебедева в портфолио калейдоскоп на флеше, покрутил по нему мышкой, понял принцип работы и подумал «ёлки, это же не сложно!».

Конечно, нельзя сказать, что это действительно очень просто. И нельзя сказать, что получилось совсем всё, что хотелось. Но есть на что посмотреть, за чем приглашаю под кат.

UPD
В посте добавил улучшенный вариант от хабрачеловека hlomzik, который не работает в ИЕ, но с меньшим кол-вом кода и с более правильным поведением.


В самом начале, я надеялся, что он будет работать совсем везде и хорошо. Не совсем получилось. В результате:
  • Firefox / Safari / Chrome — Работает идеально (кто бы сомневался).
  • IE8 — работает, но только если калейдоскоп небольшой (до 300х300). Если больше — начинает серьезно тормозить.
  • IE7 — будет работать, если добавить для него отдельный CSS в котором поправить позиционирование блоков.
  • Opera — ничерта не работает. Это отдельная песня. Сразу обращаюсь к ребятам из Оперы, которые это прочтут — посмотрите на демо и оформите это как багрепорт. В «самом быстром браузере на земле»© CSS-transform тормозит на столько безбожно, что это не лезет ни в какие ворота. И опять оперная вечная проблема — полная лажа при использовании overflow:hidden и не static-позиционированных элементах. СДЕЛАЙТЕ С ЭТИМ ЧТО-ТО!


Сразу дам ссылку на рабочий пример, чтоб было понятно, о чем вообще речь: kaleidoscope.terion.name
Итак, поехали.

Задача 1: понять, как вообще это сделать.


Калейдоскоп состоит из 12 секторов, собранных в диск. Соответственно возникает вопрос: как сделать сектор? На самом деле, это очень просто. Нам понадобится 4 блока и немного CSS. Выглядеть это должно так:
image
Блок-контейнер, один блок повернутый на -15°, внутри блок повернутый на 30°, внутри еще один повернутый на -15°.
У сектора установлена фоновая картинка, которую мы будем смещать.

Задача 2: собственно, собрать это все.


Код, соответственно очень простой:
<div class="sc s1">
  <div class="rl">
   <div class="rr">
     <div class="sv">
     </div>
   </div>
  </div>
</div>


Да, мы сразу предполагаем, что на странице может быть несколько калейдоскопов, поэтому используем только классы.
Важное условие: размер калейдоскопа должен меняться путем изменения размеров только контейнера, соответственно внутри всё должно быть в процентах.
Сразу отмечу, что значения в процентах были подобраны методом научного тыка, т.к. мои знания тригонометрии не столь глубоки, чтобы рассчитать всё это :)

  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.  
  14. .scope_container .sc div {
  15.   overflow:hidden}
  16.  
  17. .scope_container .rl {
  18.   height:110%;
  19.   width:60%;
  20.   -webkit-transform: rotate(-15deg);
  21.   -moz-transform: rotate(-15deg);
  22.   -o-transform: rotate(-15deg);
  23.   transform: rotate(-15deg);
  24.   position:relative;
  25.   top:1.5%;
  26.   left:4.5%;
  27.   
  28. }
  29.  
  30. .scope_container .rr {
  31.   height:100%;
  32.   width:100%;
  33.   -webkit-transform: rotate(30deg);
  34.   -moz-transform: rotate(30deg);
  35.   -o-transform: rotate(30deg);
  36.   transform: rotate(30deg);
  37.   position:relative;
  38.   top:7%;
  39.   left:51%;
  40. }
  41.  
  42. .scope_container .sv {
  43.   width:105%;
  44.   height:105%;
  45.   -webkit-transform: rotate(-15deg);
  46.   -moz-transform: rotate(-15deg);
  47.   -o-transform: rotate(-15deg);
  48.   transform: rotate(-15deg);
  49.   position:relative;
  50.   top:-2%;
  51.   left:-29%;
  52. }


Итак, у нас есть код для сектора. Теперь этих секторов должно быть 12 и ни должны быть завернуты в 2 контейнера, т.к. внутренний используется для позиционирования элементов, а внешний — для задания размеров и обрезки лишнего.

В итоге весь хтмл-код будет таким:

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


Классы s1 — s12 для определения положения каждого сектора.
Класс pattern определяет, какая картинка будет использована (спасибо eto_moy_nick за паттерн :) )

Расставляем блоки по местам:
  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. }
И так до 12го с шагом в 30 градусов.

В общем-то и всё.
Но ведь есть ИЕ, который всего этого не понимает! Но для ИЕ есть фильтры filter: progid:DXImageTransform.Microsoft.Matrix(...).
Поэтому, в условный комментарий [if IE 8] добавляем следующий код:

  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. }
Как показали опыты, с абсолютным позиционированием и матрицей у ИЕ беда. Поэтому пришлось такие костыли городить.

Далее:
  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.   }
И т.п.
К моему удивлению, FilterType='nearest neighbor' не принес результата (без бикубического сглаживания, скорее всего, не было бы таких тормозов).
Для расчетов матрицы я пользовался вот этим инструментом, просто спасшим мне жизнь: www.boogdesign.com/examples/transforms/matrix-calculator.html
Маржинами были вручную расставлены блоки. Если есть желание заставить это все работать в ИЕ7 — нужно лишь для него переписать эти самые маржины.

Задача 3: заставить это двигаться


Javascript. Нужно двигать фон секторов за мышкой. При этом мы помним, что калейдоскоп на странице не один. Код ниже, читаем комментарии:
  1. <script type="text/javascript">
  2.  
  3. //Мы используем классы, но ИЕ не умеет их выбирать. Компенсируем этот недостаток.
  4. if(document.getElementsByClassName) {
  5.   
  6.     getElementsByClass = function(classList, node) { 
  7.       return (node || document).getElementsByClassName(classList)
  8.     }
  9.   
  10.   } else {
  11.   
  12.     getElementsByClass = function(classList, node) {     
  13.       var node = node || document,
  14.       list = node.getElementsByTagName('*'),
  15.       length = list.length,
  16.       classArray = classList.split(/\s+/),
  17.       classes = classArray.length,
  18.       result = [], i,j
  19.       for(i = 0; i < length; i++) {
  20.         for(j = 0; j < classes; j++) {
  21.           if(list[i].className.search('\\b' + classArray[j] + '\\b') != -1) {
  22.             result.push(list[i])
  23.             break
  24.           }
  25.         }
  26.       }
  27.     
  28.       return result
  29.     }
  30.   }
  31.  
  32.  
  33. //Получаем координаты мыши
  34. function mousePageXY(e)
  35. {
  36.  var x = 0, y = 0;
  37.  
  38.  if (!e) e = window.event;
  39.  
  40.  if (e.pageX || e.pageY)
  41.  {
  42.   x = e.pageX;
  43.   y = e.pageY;
  44.  }
  45.  else if (e.clientX || e.clientY)
  46.  {
  47.   x = e.clientX + (document.documentElement.scrollLeft || document.body.scrollLeft) - document.documentElement.clientLeft;
  48.   y = e.clientY + (document.documentElement.scrollTop || document.body.scrollTop) - document.documentElement.clientTop;
  49.  }
  50.  
  51.  return {"x":x, "y":y};
  52. }
  53.  
  54.  
  55. window.onload = function() {
  56.  
  57. var scope_cont = getElementsByClass('scope_container', document);
  58.  
  59. //Калейдоскопов может быть несколько, учитываем это.
  60. for (i=0;i<scope_cont.length;i++)
  61. {
  62.   scope_cont[i].onmouseover = function() {
  63.       var sect = getElementsByClass('sv', this);
  64.       var curscope = this;
  65.       
  66.       this.onmousemove = function(e){
  67.         var mCur = mousePageXY(e);
  68.           for (n=0;n<sect.length;n++)
  69.           {
  70.             //У четных секторов фон двигается в одну сторону
  71.             if (n%2) {
  72.               sect[n].style.backgroundPosition = mCur.x + 'px ' + mCur.y + 'px';
  73.             }
  74.             //У нечетных — в другую
  75.             else {
  76.               sect[n].style.backgroundPosition = mCur.x*(-1) + 'px ' + mCur.y + 'px'
  77.             }
  78.           }
  79.           
  80.         }
  81.     }
  82.     scope_cont[i].onmouseout = function() {
  83.       //Убираем за собой, чтоб не перегружать браузер
  84.       document.onmousemove = null;
  85.     }
  86. }
  87. }
  88. </script>


В общем-то, готово.
Opera:
Если блоку .pattern добавить overflow:hidden — пропадает ВСЁ. В итоге пустая страница со скроллами в пустоту на ширину «веера».
Если overflow:hidden убрать, то в «самом быстром браузере на земле»© эта конструкция работает медленнее, чем в ИЕ.
Это полный провал.

Надеюсь, вам было интересно :)

UPD
А вот и улучшенный вариант от хабрачеловека hlomzik:
quaint.su/for/habrahabr/kaleidoscope
Обсуждение, в котором это родилось, вот: habrahabr.ru/blogs/css/99019/?reply_to=3057019#comment_3054307
Владимир @Terion
карма
0,0
рейтинг 0,0
Самое читаемое Разработка

Комментарии (102)

  • +75
    Opera всегда полный провал. Ппц, а не браузер. Кажется, идеология у них взята у ИЕ6
    • +12
      ой опасно тут такое писать, поверьте моему горькому опыту )))
      • +53
        плевать, ведь это правда!
    • +8
      +1, до сих пор даже Google Wave не работает в Опере)
      • +2
        что там вейв, гмыло у меня тупит безбожно. я уже молчу про гуглдокс.
        а жаль, нравится мне этот браузер, на слабых машинах легче всех работает
        • НЛО прилетело и опубликовало эту надпись здесь
          • –10
            С гмылом мож и нет, а вот гмайл тормозит!
          • 0
            не хочет письма удалять, вот буквально сегодня писало что-то типа «В процессе» или как-то так но не удаляет, тупо подвисает. в хроме же такое не наблюдалось ни разу. а в опере частенько, уже заметил. приходится в новом табе открывать.
            а доксах из последнего бага не сохранялся документ. после этого я понял что гуглосервисами лучше пользоваться из хрома.
            плюс виджет Gmail Checker куда-то из оперы пропал. никто не знает почему этот виджет удалили?
            • НЛО прилетело и опубликовало эту надпись здесь
              • +2
                сколько компьютеров столько и мнений :)
              • +1
                и кстати, не хватает главной роскоши — драг-энд-дроп вложений в письмо!
            • 0
              У меня такая же проблема в опере под убунтой. Последняя опера вообще безбожно затупляет на несколько секунд при открытии страницы. В 10.11 gmail тупит при открытии/удалении писем. Пишет «Еще работаем» и всё. Грешу на работу с прокси.
    • НЛО прилетело и опубликовало эту надпись здесь
      • –2
        Да, Опера до него не дотягивает. Но старается изоВсехСил
      • +13
        С осликом другая ситуация. Если вы опытный технолог, то проблем с осликом мало (все явные баги ослика давно изучены и описаны + есть куча вариантов их профиксить (conditional comments, expressions, behavior, filters, hasLayout, хаки наконец).

        С Оперой совсем другая песня. Когда встречаешь какой-нибудь баг в Опере то практически всегда, во-первых, не понимаешь из-за чего так, во-вторых, сложно найти триггер бага, в-третьих, тупо не знаешь как фиксить да и вариантов особых нет, хаков для Оперы рабочих практически не существует. В JS еще можно сделать что-то типа if (window.opera)… а в CSS остается только переверстывать. А если еще учесть, что опера довольно часто обновляется, и что с каждой новой версией багов, как правило, становится больше, то это просто кошмар.

        Плюс, у меня сложилось стойкое ощущение, что у них регрессивные и старые баги (типа глюков display:inline-block у элементов с position отличным от static, не всегда происходящим repaint/reflow, глюков с регулярными выражениями, глюков с overflow:hidden) имеют низший приоритет. Я точно знаю, что баги эти все по 10 раз зарепортены. Невозможно так долго на это забивать.
        • +1
          а еще дробные значения в ксс, из-за которого опера не может пройти ACID1. Интересно, из ACID2 этот тест специально убрали?
          • 0
            Ну про дробные проценты я вообще не говорю. Этот баг тянется с самого зарождения Оперы. И все про него знают. Разработчики все обещают и обещают профиксить, сначала в 9, потом в 10, потом в 10.50 но так и не фиксят.
            • +3
              надо было оставить в Acid2, поменьше выпендривались бы и делом занимались бы. ато подогнали под оперу тест и они размякли
            • 0
              еще к этому добавляется масса багов с оверфловами… которые вылазят нечасто, но если уже вылазят — то пофиксить это невозможно :(
        • НЛО прилетело и опубликовало эту надпись здесь
        • 0
          CSS-хаки для «Оперы» есть. Я, например, придумал несколько.
          • 0
            Они работают только на каких-то конкретных версиях. Так как версии Оперы часто меняются, и баги/фичи на которых построены хаки исправляются, это не совсем хороший выход. Идеально было бы иметь что-то типа CC для IE или же специфические эт-правила (как @-moz-document).
            • 0
              Например, для «Оперы» 10.50+ CSS hack работает и будет работать очень долго, он не на баге построен.
    • +1
      Opera 10.6 — это провал. Плагин sortable к jquery — нормально них не работает
  • +2
    Браво!
    • +3
      спасибо :)
  • 0
    заворожил ваш калейдоскоп. спасибо, может и пригодится когда-то!
    • +1
      буду рад)
  • 0
    Было интересно. =) Но на флэше получается быстрее, проще и без проблем с оперой.
    • +4
      ой опасно тут такое писать :)
      • +4
        Следует бояться владельцев айпада? ) В айфоновской сафари не рабоатет, проверил только что. Хотя кто-бы сомневался.
        • 0
          В хроме под андроидом 2.1 работает, правда не так шустро как хотелось бы, обновляется целую секунду.
          • 0
            а как он работает, интересно? там же неоткуда взяться событию onmousemove?
            • 0
              Сам удивился, отрабатывает по клику.
        • 0
          хм. интересно, не работает совсем? т.е. рассыпалось? или просто нет анимации?
          • 0
            Не развалилось, просто нет событий мыши.
            • 0
              ну это логично ))
    • +2
      ну оно-то да)
      но надо же было попробовать)
    • 0
      Интересно было бы получить комментарии минусующих, что именно вас так задело? =)
      • –1
        Всего один минус, что именно тебя так задело?
  • +4
    требую от автора: под какой лицензией вы это даете юзать?!!!

    спасибо за практикум по JS!
    спасибо огромное за статью!
    • +8
      берите на здоровье и делайте с ним что хотите)
      • +8
        БНЗИДСМНЧХ
        Ваша лицензия – самая крутая)
        • +2
          ))))))
          нужно предложить эту лицензию в рамках Creative Commons)
  • НЛО прилетело и опубликовало эту надпись здесь
    • 0
      ээ… не понял
      • 0
        Подразумевается, что в «правильном» калейдоскопе каждый сектор является отражением соседнего. Условно говоря, четные сектора — это сектора из исходного изображения (у вас все сектора из исходного), а нечетные — из изображения, зеркального к исходному. Это гарантирует совпадение краев секторов (как это происходит к классическом калейдоскопе). Правда сделать отражение изображения средствами лишь CSS — проблематично.
        • 0
          хммм… ну, если скормить две картинки, то над таким можно подумать…
          а вообще, возможно стоит реализовать такой калейдоскоп на канвасе, там и отражение сделать можно будет
          • 0
            Чёрт! Продолжим…
            webkit.org/blog/182/css-reflections/
            • +1
              И опять мимо! :-)
            • 0
              Ну да, это бы помогло в плане спасения от канваса и дублирования картинок, но поддержка этого свойства пока еще довольно слабая.
            • 0
              ну так только сафари же… и то, не спасет.
              можно попробовать SVG/VML, не помню, есть ли у них флипы… если есть, можно использовать их элементы вместо дивов…
        • 0
          О, вот, оказывается, для чего разумного можно применить
        • 0
          Ну просто придется 2 картинки взять: зеркальную и обычную.
          • 0
            Посетила мысль… можно ведь той же трансформ-матрицей сделать зеркальное отображение!
            • 0
              Так, собственно, в этой флешке и сделано.
            • 0
              хм… да? вы уверены? надо будет погуглить… а то я в этих матрицах так ничерта и не понял…
              • 0
                Я это делал. ;)
                • 0
                  а можно какой-то гайд?
                  • 0
                    -1  0  0
                     0  1  0
                     0  0  1
                    отражение по горизонтали.
                    • 0
                      хм. спасибо) буду курить матрицы…
              • 0
                Да

                -1 0
                0 1

                Да там понимать нечего. Матрица
                a b
                c d

                Xновый = Xстарый * a + Yстарый * b
                Нновый = Xстарый * с + Yстарый * d
  • 0
    шикарно, осталось только придумать куда приспособить)
  • 0
    Очень хорошо :) Я сам в последнее время иногда балуюсь как раз примерно с тем же — ротейтом блоков с фоном и у меня получалось побороть оперную хрень с непоказывающимся фоном при overflow:hidden прописывая картинку блоку через content:url(…), правда, в таком случае, придётся лишний блок использовать, т.к., понятное дело, никакого background-position не будет.
    • 0
      учитывая то, как оно тормозит в опере — лучше вообще не показывать…
      но тем не менее, на будущее — пропадает именно фон? т.е. если в блоках будет контент — он не пропадет?
      • 0
        Контент будет. А пропадает даже не именно фон, а именно картинка в фоне — если заданы и цвет фона и картинка, то картинки не будет, а цвет будет.
        • 0
          вот как… Ясно, спасибо, полезная информация
  • 0
    Спасибо очень интересная статья.

    Про Оперу вы баг репорт можете отправить если не сложно? https://bugs.opera.com/wizard/
    • 0
      будет багрепорт)
      надо бы только более подробно изучить баг. Вон, kizu новую инфу подогнал. Надо еще покурить
  • +1
    Может Опера тормозит по сравнению с остальными, т.к. в ней самое красивое сглаживание получается при трансформациях?
    www.useragentman.com/blog/2010/03/09/cross-browser-css-transforms-even-in-ie/
    • +1
      да к чертям эту красоту ценой такого падения производительности!
      к тому же в фаерфоксе сглаживает прекрасно и ничего не тормозит.
      в хроме под маком тоже.
      в хроме под виндой — вообще не сглаживает, да.
  • 0
    Сразу обращаюсь к ребятам из Оперы, которые это прочтут — посмотрите на демо и оформите это как багрепорт.
    Вы можете сделать это сами за секунду. На той странице, где отображается что-то неверно, зайдите в «Справку» -> «Сообщить о проблеме с сайтом…»
    • +1
      Это — слишком длинный путь к разработчику. Придётся ждать, пока дойдёт дело до вашей жалобы, а потом кто-то из тестировавших должен будет сам написать рапорт об ошибке :-)
      Лучше сразу сюда, если не лень: https://bugs.opera.com/wizard/
    • 0
      fatal всё правильно сказать, лучше пользоваться визардом.
  • 0
    Интересная работа, буду сейчас разбирать, спасибо.
  • 0
    А в калькуляторе ничего уж такого жизнеспасающего: всего-то синус и косинус считает :D
    cos(A), sin(A), sin(A), cos(A)
    • 0
      упс, перед первым синусом "-" потерял
    • 0
      та оно-то да, но я так и не могу вкурить эти чертовы матрицы.
      да и согласитесь, указать градус и тыцнуть кнопку — много быстрее, чем считать вручную)
      • 0
        Посмотрите в спецификации SVG, там достаточно легко для понимания описано.
  • НЛО прилетело и опубликовало эту надпись здесь
  • 0
    Сектор можно сделать из двух блоков, на схеме это два наклонённых прямоугольника — в одном фон, второй отрезает нужный кусочек. Ну и можно оставить контейнер, если он действительно нужен, но не думаю, что он незаменим.

    Вращение можно попробовать сделать вкладывая один сектор в другой, задавая относительное вращение каждого в 30 градусов.

    Как уже выше сказали, изображение отражается от граней, стоит хотя бы сделать зеркальную картинку для нечётных граней. На деле там всё ещё сложнее, что и даёт замечательные эффекты :)

    Ещё можно попробовать сделать перемешивание без js, с помощью background-attachment; при этом для перемешивания калейдоскопа его в прямом смысле надо будет трясти в стороны :)
    • –1
      «Сектор можно сделать из двух блоков, на схеме это два наклонённых прямоугольника — в одном фон, второй отрезает нужный кусочек.»
      — нет нельзя, потому что фон тогда под углом будет.

      «Ну и можно оставить контейнер, если он действительно нужен, но не думаю, что он незаменим.»
      — нет, он нужен, потому что иначе прийдется рассчитывать углы индивидуально для каждого повернутого блока, что будет полной лажей.

      «Вращение можно попробовать сделать вкладывая один сектор в другой, задавая относительное вращение каждого в 30 градусов.»
      — что приведет к еще большим нагрузкам на браузер

      «Как уже выше сказали, изображение отражается от граней, стоит хотя бы сделать зеркальную картинку для нечётных граней. На деле там всё ещё сложнее, что и даёт замечательные эффекты :)»
      — я эту фишку калейдоскопов вообще не заметил )))

      «Ещё можно попробовать сделать перемешивание без js, с помощью background-attachment; при этом для перемешивания калейдоскопа его в прямом смысле надо будет трясти в стороны :) »
      — да вы, батенька, извращенец ))))
      • 0
        нет нельзя, потому что фон тогда под углом будет.
        эм, не думаю, что это так критично, на цветочном орнаменте смотрится так же нормально)
        а лучше вообще прямоугольники поворачивать на 0 и 30 градусов, тогда обрезается повёрнутым прямоугольником, а фон остаётся в нормально спозиционированном.
        Сразу отвечу на комментарий ниже повтором — четвертый блок не нужен совсем :)

        нет, он нужен, потому что иначе прийдется рассчитывать углы индивидуально для каждого повернутого блока, что будет полной лажей.
        внутренние блоки поворачиваются относительно родителя? если да, то нумерованные классы можно проставить одному из наклонных блоков (внешнему), опять же — оставив всего два контейнера.

        что приведет к еще большим нагрузкам на браузер
        да, избавляюсь от лишних блоков, а тут ступил… не нужно, ок :)
        • 0
          «м, не думаю, что это так критично, на цветочном орнаменте смотрится так же нормально)»
        • 0
          отправилось случайно.
          так вот:

          «м, не думаю, что это так критично, на цветочном орнаменте смотрится так же нормально)»
          он не только будет стоять под углом, но и сдвигаться под углом, что есть неправильно
          • +3
            Эм, о чём мы вообще говорим? Под каким углом? У нас все сектора под углом. И два блока правда не нужны :)
            Я таки сделал рабочий пример: quaint.su/for/habrahabr/kaleidoscope/
            И там сделано зеркальное отражение, выглядит круто! Правда, тут виден плюс общего контейнера для сектора — матрицу можно было бы задать в одном месте для первого повёрнутого прямоугольника через .sc:nth-child(even) .rl{...}
            Но этили лучше всё равно прописывать на js, так что без разницы.

            С background-attachment проблемка — Fx не перерисовывает блоки с css-transform при изменении позиции, так что дальше ковырять не стал.
            • 0
              1. отражение в хроме не работает
              2. под обычным углом! боковое смещение картинок должно быть относительно «лучей», т.е. относительно медианы сектора! у вас же боковое смещение относительно одной из сторон сектора!
              • +2
                1. Забыл для всех браузеров циферки поменять, теперь работать должно.
                2. Это калейдоскоп, там картинки перемешиваются! Смещение будет очевидно только при mousemove в первом секторе. Но я всё равно поправил, теперь поведение совсем как у вас было.
                • +2
                  а вот теперь действительно круто.
                  только в ИЕ не пашет )))
                  ну да ладно.
                  Сделаю апдейт к посту.
                  Вы молодец =)
                  • 0
                    Я кусок для ие вообще убрал… Там нужно перемножить матрицы, которые есть сейчас, на матрицу, которую я указал выше (первые две строки только, конечно), причём я постоянно путаю, в какой последовательности, надо оба варианта испробовать. В общем, просто было лениво:)
                    • 0
                      кстати, все равно смещение фона относительно стороны, а не медианы )))
                      т.е. если все-таки не упразнять блоки, то выйдет еще правильней ))
                      но да, оно не особо заметно
                      • 0
                        Здесь нужно смещение относительно общего контейнера (неясно — зачем). В вашем случае с вертикалью совпадала медиана первого сектора, в моём — его вертикальная сторона. Т.е. если будете водить мышью по первому сектору (справа от вертикали внизу), то паттерн будет двигаться ровно за мышкой, как и у вас.
                        • 0
                          в том-то и дело, что по-правильному смещение должно быть перпендикулярно медиане видимого сектора.

                          у меня оно не совпало так, я именно для этого и добавил внутрь еще один блок.

                          т.е. если идеально правильный калейдоскоп будет если добавить отражение (как у вас) и смещать относительно медианы сектора (как у меня)
                          • 0
                            Что такое видимый сектор? О какой правильности смещения можно говорить, когда в одном предложении игрушка калейдоскоп и компьютерная мышь? ;) По правильному у нас должно быть несколько геометрических примитивов, которые будут перемешиваться при встряске калейдоскопа)

                            У меня относительный поворот калейдоскопа относительно вашего — 15 градусов. Если я сделаю смещение относительно медианы, то не будет прямой интуитивной связи движений мышки и движений рисунка, т.е. мышка будет как зерно в генераторах случайных чисел (хотя на самом деле я за такое поведение ;) ). У меня сделана привязка координат рисунка одного сектора к системе координат вьюпорта (как и у вас) — это соответствует физике этого мира :) В настоящем калейдоскопе незеркальный сектор обычно определить было невозможно, и «ортогональным» сектором может быть любой.
                • 0
                  в ФФ швы полезли(
    • 0
      хотя да, можно четвертый блок упразнить, сгенерировав его в CSS при помощи того же :before
      но вот стучаться к нему яваскриптом будет проблематично, да и опять же, на сколько мне известно, это понизит производительность (хотя тут могу ошибаться — чисто субъективные наблюдения)
  • 0
    Возил мышкой минут 20… вспомнил игрушку с детства. :)
    • 0
      гипноскоп ^_^ ))
  • 0
    красота!
    • 0
      пасиб )
  • 0
    Большое спасибо, за хорошую статью. Как раз появилась необходимость создать калейдоскоп.
  • 0
    Ухх. Тёмный калейдоскоп со второго примера выбитыми пикселями пугает.

Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.