Внедрить слайд-шоу/карусель только для CSS с помощью следующих и предыдущих кнопок?

В течение некоторого времени, выключен и включен, я пытался реализовать слайд-шоу только для CSS, которое:

  • Предложите навигацию вперед и назад.
  • Не изменять историю навигации.
  • Определите направление движения содержимого.
  • Работайте как можно большим количеством браузеров.

Большинство других слайд-шоу CSS, с которыми я столкнулся, не отметили все эти поля.

К счастью, мне так долго приходилось, что сами браузеры улучшились без конца, до такой степени, что сейчас это довольно широко, хотя и с несколькими "современными" CSS-измами. На всякий случай это полезно кому-то еще, я подумал, что отправлю его здесь.

Итак, как вы можете создать навигационное слайд-шоу, используя только CSS и следующую разметку?

<ul class="css-slider">
  <li class="slide"><img src="photos/a.jpg" /></li>
  <li class="slide"><img src="photos/b.jpg" /></li>
  <li class="slide"><img src="photos/c.jpg" /></li>
  <li class="slide"><img src="photos/d.jpg" /></li>
  <li class="slide"><img src="photos/e.jpg" /></li>
</ul>

Ответ 1

simple screenshot

рабочий пример

http://jsfiddle.net/q4d9m/2/

ОБНОВЛЕНИЕ: Кажется, есть ошибка с Firefox 32 (Mac), что означает, что эллипсы не будут отображаться в SVG, это приводит к сбою отражения... и не заставляйте меня начинать с того, что делает Chrome 37.0.2062.120 (Mac), если вы наведете на него какие-либо изображения в реализованном примере в нижней части этого ответа.

— 18 сентября 2014 года.


, объясняя основной принцип

Слайды создаются из двух основных частей, визуальной части и интерактивной части. Интерактивная часть в значительной степени остается статической, а визуальная часть анимирована. После многократного воспроизведения я расширил исходную структуру HTML (см. Выше), чтобы включить несколько дополнительных оберток вокруг содержимого слайдов. Это позволяет использовать отдельные интерактивные и визуальные части, а также дополнительную гибкость для других полезных способностей, например вертикальное центрирование и отражения.

<ul class="css-slider">
  <li class="slide" tabindex="1" id="l1">
    <span class="slide-outer">
      <span class="slide-inner">
        <span class="slide-gfx" id="s1">
          <img src="photos/a.jpg" />
        </span>
      </span>
    </span>
  </li>
  <li class="slide" tabindex="1" id="l2">
    <span class="slide-outer">
      <span class="slide-inner">
        <span class="slide-gfx" id="s2">
          <img src="photos/b.jpg" />
        </span>
      </span>
    </span>
  </li>
  ...
</ul>

Теперь, чтобы на самом деле любая система вела себя как слайд-шоу, вам нужно каким-то образом определить текущий или сфокусированный слайд. В этом случае im полагается на :focus, чтобы справиться с этим различием. Возможно, вы заметили добавление tabindex="1" выше, это значит, что псевдокласс :focus применяется к неожиданным элементам, таким как <li> — это требовалось главным образом для браузеров, основанных на веб-страницах, но может помочь и другим агентам.

Итак, все слайды уложены друг на друга друг на друга, текущий сфокусированный слайд центрирован в окне просмотра и задан самый высокий z-index, слайд перед сфокусированным слайдом переведен с экрана влево, и слайд после фокусированного слайда переведен с экрана вправо. Следует отметить, что переводы xy влияют только на визуальный контент слайдов, интерактивные части по-прежнему накладываются друг на друга, заполняя всю область области просмотра, а почти...

illustration of previous, next and current slides

Я говорю почти потому, что для того, чтобы фокус срабатывал на следующем и предыдущем слайдах — с помощью мыши или touch — часть их интерактивных слоев должна быть доступной и доступной пользователю. Используя смесь left, right и padding, можно выявить правильные области, не вытесняя визуальные элементы.

snippets of key css

Итак, поскольку текущий сфокусированный слайд изменяется, также доступны области интерактивных слоев. Каждый раз, когда пользователь нажимает следующую или предыдущую стрелки, они фактически фокусируются на соседнем элементе <li>, а не на ссылке, которая выполняет какие-либо действия.

illustration of interactive layer positioning


полезно знать

  • Чтобы заставить это работать в браузерах Webkit, необходимо использовать атрибут tabindex, чтобы псевдо-класс :focus работал на любом базовом элементе, который вы используете для представления слайда.

  • Из-за используемых трюков слайды будут играть в обратном порядке.

  • Вы можете перемещаться по слайд-шоу с помощью вкладки, однако он будет перемещаться назад, из-за пункта 2. Если у вас есть Mac, вам может потребоваться настроить настройки os перед тем, как вкладка будет работать.

  • Из-за трюка left, right, чтобы выставить стрелки навигации, при навигации вперед или вправо появляется небольшой визуальный сбой; в котором вы можете увидеть, как последующая предыдущая стрелка быстро окунается на место.

  • Поскольку эта система работает на основе :focus, когда фокус теряется, слайд-шоу возвращается к исходному слайду, поэтому подзаголовки не будут работать в ваших слайдах — если вы не улучшите взаимодействие с JavaScript.

  • В моей демонстрации используются фоновые изображения SVG, они, очевидно, являются необязательными и не работают в старых браузерах.


поддерживается

  • Firefox v26.0 (Mac/PC ~ скорее всего гораздо более ранние версии)
  • Chrome v32 (Mac/PC ~, скорее всего, гораздо более ранние версии)
  • Safari v7 (Mac/PC ~ скорее всего гораздо более ранние версии)
  • Opera v18 (Mac/PC ~, скорее всего, гораздо более ранние версии)
  • Internet Explorer 9+ (ПК)

IE7 и IE8 даже не могут понять :last-child или :nth-child, так что нет, для них работает не.


добавлены дополнительные функции

В приведенной ниже демонстрации вы увидите, что есть несколько расцветов JavaScript, они либо помогают показать, что может сделать конструктор, либо постепенно прогрессировать. Флажки, которые есть только для демонстрации, должны позволить вам включать или отключать определенные функции. Эти функции применяются с помощью простых классов:

  • .with-responsive-images ~ немного взломать, чтобы заставить изображения авторизоваться.
  • .with-selection-disabled ~ предотвращает перетаскивание и выделение пользователем.
  • .width-fade-in ~ изначально исчезает слайд-шоу.
  • . с рефлексией ~ позволяет отражать firefox и webkit.
  • .with-slide-zoom ~ при наведении слайдов будет увеличиваться до максимальной ширины.
  • .with-slide-float ~ при фокусировке слайды будут левитировать.
  • .with-slide-float-hover ~ при наведении слайдов будет левитировать.
  • .with-shadow ~ отражение поормана.

обратите внимание: надстройка отражения зависит от произвольных атрибутов разметки. Вам нужно будет добавить уникальные идентификаторы для каждого .slide, а затем расширить CSS, чтобы принять их во внимание.


распад CSS

настройки

Хорошо, так что для начала - базовая настройка. Во-первых, потому что мое слайд-шоу с изображениями, я установил некоторый базовый стиль изображения, это все необязательно.

.slide-gfx img {
  max-width: 600px;
  max-height: auto;
  border-radius: 20px;
  box-shadow: 0 0 80px rgba(255,255,255,1);
}

Маска ползунка была добавлена ​​как обертка во все слайд-шоу, чтобы предотвратить отображение полосы прокрутки окна при работе с слайд-шоу в полноэкранном режиме. Это необязательно.

.css-slider-mask {
  display: block;
  overflow: hidden;
  width: 100%;
  height: 100%;
}

Теперь мы получаем фактическую настройку, необходимую для ползунка. Эта первая часть довольно проста, за исключением части display: none;. Сначала он скрывает слайд-шоу от всех, но затем переопределяется для браузеров, поддерживающих :nth-child. Скорее всего, ваш элемент <body> будет вторым ребенком, но вы должны проверить его перед использованием.

.css-slider {
  list-style: none;
  margin: 0;
  padding: 0;
  width: 96%;
  height: 100%;
  margin-left: 2%;
  z-index: 1;
}

.css-slider {
  position: relative;
  display: none;
}

body:nth-child(2) .css-slider {
  display: block;
}


слайды

Далее мы переходим к слайдам. Из-за отсутствия реверсивного General Sibling Selector (~) все стили по умолчанию для слайдов представляют собой будущее (или следующее) состояние, Это связано с тем, что нет реального способа выбора будущих слайдов.

.css-slider .slide {
  display: block;
  position: absolute;
  left: 40px;
  top: 0;
  right: 0;
  bottom: 0;
  padding-left: 0;
  padding-right: 40px;
  z-index: 100;
  outline: 0; /* kill the focus rect! */
}

Опять же, по умолчанию мы создаем прямую стрелку, а затем переопределяем ее для текущих и прошлых слайдов.

.css-slider .slide {
  background: url('arrow-right.svg') no-repeat right center;
  background-size: 25px auto;
}

.css-slider .slide:hover {
  background-image: url('arrow-right-hover.svg');
  cursor: pointer;
}

Теперь сфокусированный слайд, ключевые элементы здесь :focus (как я уже объяснил) и :last-child, которых у меня нет. Последний ребенок используется, а не Первый ребенок, потому что снова мы должны работать назад (все из-за отсутствия обратного General Sibling Selector ~). Почему любой ребенок вообще нужен, так что мы можем "сфокусировать" начальный слайд, когда нет фокуса, то есть при загрузке страницы.

.css-slider .slide:target,
.css-slider .slide:target:hover,
.css-slider .slide:focus,
.css-slider .slide:focus:hover,
.css-slider .slide:last-child,
.css-slider .slide:last-child:hover {
  left: 40px;
  right: 40px;
  padding-left: 0;
  padding-right: 0;
  background: transparent;
  z-index: 101;
  cursor: default;
}

Теперь нам нужно затронуть все слайды, которые проскальзывают в прошлое. Я до сих пор избегал упоминания псевдо-класса :target, в основном это было реализовано для поддержки "прыгающего nav". Есть две причины, по которым я не буду петь хвалу "прыжковой наки":

  • Он частично работает на JavaScript.
  • Он полагается на значения #hash или #fragment, которые из-за создания состояний истории могут возиться с юзабилити вашего сайта.

Во всяком случае, трюк для выбора слайдов, которые были в прошлом, зависит от General Sibling Selector. Следующая конструкция в основном означает select.slide(s), который вы найдете после .slide, который имеет: focus.

.css-slider .slide:target ~ .slide,
.css-slider .slide:focus ~ .slide {
  padding-left: 40px;
  padding-right: 0;
  left: 0;
  right: 40px;
}

.css-slider .slide:target ~ .slide,
.css-slider .slide:focus ~ .slide {
  background: url('arrow-left.svg') no-repeat left center;
  background-size: 25px auto;
}

.css-slider .slide:target ~ .slide:hover,
.css-slider .slide:focus ~ .slide:hover {
  background-image: url('arrow-left-hover.svg');
}


содержание слайдов

Затем мы должны контролировать, что именно происходит с нашим содержимым слайдов. Я разработал эту систему, чтобы, если вы захотите, вы можете оставить раздел анимации. Это будет означать, что слайды будут переключаться мгновенно. Эта следующая часть позаботится об этом.

.css-slider .slide .slide-outer {
  display: none;
  width: 100%;
  height: 100%;
}

Slide-inner используется исключительно для обработки центрирования содержимого слайдов. Он использует дисплей table и отображает table-cell.

.css-slider .slide .slide-outer .slide-inner {
  display: table-cell;
  vertical-align: middle;
  text-align: center;
  width: 100%;
  height: 100%;
}

Slide-gfx - это буквально только содержащая оболочка для всех, что вы решили разместить в своем слайд-шоу. Отражение генерируется из этого контейнера, и к нему также прикрепляются несколько других визуальных дополнений.

.css-slider .slide .slide-outer .slide-inner .slide-gfx {
  position: relative;
  display: inline-block;
  z-index: 102;
  text-align: left; /* override the centering back to defaults */
}

Эта часть отвечает за мгновенный переключатель, если анимация не включена.

.css-slider .slide:target .slide-outer,
.css-slider .slide:focus .slide-outer,
.css-slider .slide:last-child .slide-outer {
  display: block; /* if they don't support display table */
  display: table;
}


переопределения последнего и последнего времени

Из-за объявлений :last-child, которые входят, когда ничего не сфокусировано, если вы не должны вносить дальнейшие изменения, вы обнаружите, что некоторые вещи ломаются. Это связано с тем, что :last-child всегда применяется, в отличие от :focus. Чтобы исправить это, нам нужно отрицать изменения :last-child, но только тогда, когда что-то было сфокусировано. Это то, что делает следующий CSS.

.css-slider .slide:target ~ .slide:last-child,
.css-slider .slide:focus ~ .slide:last-child {
  cursor: pointer;
}

.css-slider .slide:target ~ .slide:last-child .slide-outer,
.css-slider .slide:focus ~ .slide:last-child .slide-outer {
  display: none;
}


окончательный раздражающий z-index hack

До сих пор CSS был довольно обобщен, но всегда есть что-то...

Эта часть требуется только для исправления щелчка стрелки "предыдущего слайда", так что последний предыдущий кадр всплывает над чем-либо еще. Если вы не заботитесь о предыдущем действии слайдов, вы можете покончить с этим шагом, пока вы скрываете предыдущую стрелку. Это довольно раздражает, потому что весь этот произвольный раздел может быть устранен, если CSS поддерживает инвертированную версию General Sibling Selector.

В основном следующее будет поддерживать до 5 кадров, если вам нужно больше, добавьте больше. По крайней мере, хорошая новость заключается в том, что вы можете добавить гораздо больше кадров, чем вам нужно, без каких-либо реальных неблагоприятных эффектов. Очевидно, что если вы перейдете к 100 кадрам, вам придется настроить другие z-индексы в остальной части CSS.

.css-slider .slide:target ~ .slide:nth-child(1),
.css-slider .slide:focus  ~ .slide:nth-child(1) { z-index:99; }
.css-slider .slide:target ~ .slide:nth-child(2),
.css-slider .slide:focus  ~ .slide:nth-child(2) { z-index:98; }
.css-slider .slide:target ~ .slide:nth-child(3),
.css-slider .slide:focus  ~ .slide:nth-child(3) { z-index:97; }
.css-slider .slide:target ~ .slide:nth-child(4),
.css-slider .slide:focus  ~ .slide:nth-child(4) { z-index:96; }
.css-slider .slide:target ~ .slide:nth-child(5),
.css-slider .slide:focus  ~ .slide:nth-child(5) { z-index:95; }


Анимация и надстройки

Как я уже сказал, анимация является необязательной, наряду со всеми остальными визуальными надстройками CSS. Я включу остальные здесь с меньшими деталями. Большинство из них довольно прямолинейны, как только вы узнаете трюки выше и переходы CSS или анимации. Основная причина для него - это, как обычно, префиксы поставщика; который я удалил для краткости. Чтобы указать полный CSS, вы, очевидно, можете сделать это из демонстрации ниже.

обратите внимание:. Большинство этих надстроек полагаются на довольно современные CSS, т.е. анимации или SVG.

/** --------------------------------------------------------------------------
 * HANDLE THE SLIDE ANIMATION (optional)
 * ------------------------------------------------------------------------ */

/* Override the default instant slide behaviour */
.css-slider .slide .slide-outer {
  display: block !important;
  display: table !important;
}

/* set up the transitions */
.css-slider .slide .slide-outer {
  transition-property:                opacity, transform;
  transition-duration:                2s;
  transition-timing-function:         ease;
}

/* After state */
.css-slider .slide:target ~ .slide .slide-outer,
.css-slider .slide:target ~ .slide:last-child .slide-outer,
.css-slider .slide:focus ~ .slide .slide-outer,
.css-slider .slide:focus ~ .slide:last-child .slide-outer {
  transform: translate(-150%,0);
  transform: translate3D(-150%,0,0);
}

/* Before state */
.css-slider .slide .slide-outer {
  transform: translate(200%,0);
  transform: translate3D(200%,0,0);
}

/* Focused state*/
.css-slider .slide:target .slide-outer,
.css-slider .slide:focus .slide-outer,
.css-slider .slide:last-child .slide-outer {
  transform: translate(0,0);
  transform: translate3D(0,0,0);
}

/** --------------------------------------------------------------------------
 * SMALL SCREEN FIX / SLIDE JERK (optional)
 * ---------------------------------------------------------------------------
 * When we shift 'left' and 'right' values -- in order to allow access to a future
 * or past arrow -- this can cause a jump in the responsive scaling of the slide.
 * if we transition the left value quickly, it can make this appear less jarring.
 */

.css-slider .slide {
  transition-property:        left, padding-left;
  transition-duration:        1s;
  transition-timing-function: ease;
}

/** --------------------------------------------------------------------------
 * Add-on module : responsive images
 * ------------------------------------------------------------------------ */
.with-responsive-images .slide-gfx img {
  width: 100%;
  height: auto;
}

/** --------------------------------------------------------------------------
 * Add-on module : stop user selection
 * ------------------------------------------------------------------------ */

/* if your slides don't need to be selectable, I recommend using this */
.with-selection-disabled {
  user-select: none;
}

/** --------------------------------------------------------------------------
 * Add-on module : initial fade in 
 * ------------------------------------------------------------------------ */
.with-fade-in .slide-gfx {
  opacity: 0;
}

/* animate into visibility */
.with-fade-in .slide-gfx {
  animation:           css-slideshow-fade-in 2s;
  animation-delay:     1s;
  animation-fill-mode: forwards;
}

/* Vebdor animations */
@keyframes css-slideshow-fade-in { from { opacity: 0; } to { opacity: 1; } }

/** --------------------------------------------------------------------------
 * Add-on module : slide reflection
 * ------------------------------------------------------------------------ */

/* force our slide-gfx to be inline-block and relative positioned */
.with-reflection .slide-gfx {
  display: inline-block !important;
}

/* reflection for webkit agents */
.with-reflection .slide-gfx > *:first-child {
  -webkit-box-reflect: below 2px 
        -webkit-gradient(linear, left top, left bottom, 
           from(transparent), color-stop(0.9, transparent), to(white));
}

/* make sure internal images don't keep inline spacing/margin */
.with-reflection .slide-gfx img {
  display: block;
}

/* generate the reflection */
.with-reflection .slide-gfx:after {
  content: '';
  position: absolute;
  display: block;
  mask: url("reflection-mask.svg#mask"); /* gradient fade the reflection */
  transform: scaleY(-1); /* flip clone to appear as reflection */
  opacity: 0.5; /* fade out reflection */
  top: 100%;
  width: 100%;
  height: 60px;
  z-index: 200;
  margin-top: 2px;
}

/* again, due to element() requiring IDs we need arbitrary code 
   per each slide and each slide-gfx needs an id */
.with-reflection #s1:after { background: -moz-element(#s1) no-repeat left bottom; }
.with-reflection #s2:after { background: -moz-element(#s2) no-repeat left bottom; }
.with-reflection #s3:after { background: -moz-element(#s3) no-repeat left bottom; }
.with-reflection #s4:after { background: -moz-element(#s4) no-repeat left bottom; }
.with-reflection #s5:after { background: -moz-element(#s5) no-repeat left bottom; }
.with-reflection #s6:after { background: -moz-element(#s6) no-repeat left bottom; }
.with-reflection #s7:after { background: -moz-element(#s7) no-repeat left bottom; }
.with-reflection #s8:after { background: -moz-element(#s8) no-repeat left bottom; }
.with-reflection #s9:after { background: -moz-element(#s9) no-repeat left bottom; }
.with-reflection #s10:after { background: -moz-element(#s10) no-repeat left bottom; }
.with-reflection #s11:after { background: -moz-element(#s11) no-repeat left bottom; }
.with-reflection #s12:after { background: -moz-element(#s12) no-repeat left bottom; }
.with-reflection #s13:after { background: -moz-element(#s13) no-repeat left bottom; }
.with-reflection #s14:after { background: -moz-element(#s14) no-repeat left bottom; }
.with-reflection #s15:after { background: -moz-element(#s15) no-repeat left bottom; }
.with-reflection #s16:after { background: -moz-element(#s16) no-repeat left bottom; }
.with-reflection #s17:after { background: -moz-element(#s17) no-repeat left bottom; }
.with-reflection #s18:after { background: -moz-element(#s18) no-repeat left bottom; }
.with-reflection #s19:after { background: -moz-element(#s19) no-repeat left bottom; }
.with-reflection #s20:after { background: -moz-element(#s20) no-repeat left bottom; }

/** --------------------------------------------------------------------------
 * Add-on module : slide zoom (optional, not compatible with slide float)
 * ------------------------------------------------------------------------ */
.with-slide-zoom .slide .slide-gfx > *:first-child {
  transition-property:                max-width;
  transition-duration:                2s;
  transition-timing-function:         ease-in-out;
  transition-delay:                   0.25s;
}

.with-slide-zoom .slide .slide-gfx > *:first-child:hover {
  max-width: 1000px;
}

/** --------------------------------------------------------------------------
 * Add-on module : slide float (optional, not compatible with slide zoom)
 * ------------------------------------------------------------------------ */

/* inital transition set-up */
.with-slide-float:not(.with-slide-zoom) .slide .slide-gfx > *:first-child,
.with-slide-float-hover:not(.with-slide-zoom) .slide .slide-gfx > *:first-child {
  transition-property:        transform;
  transition-duration:        2s;
  transition-timing-function: ease-in-out;
}

/* we need a delay for the non-hover version */
.with-slide-float:not(.with-slide-zoom) .slide .slide-gfx > *:first-child {
  transition-delay: 2s;
}

/* initial levitation on focus */
.with-slide-float:not(.with-slide-zoom) .slide:target .slide-gfx > *:first-child,
.with-slide-float:not(.with-slide-zoom) .slide:focus .slide-gfx > *:first-child,
.with-slide-float-hover:not(.with-slide-zoom) .slide .slide-gfx > *:first-child:hover {
  transform: translate(0,-40px);
  transform: translate3D(0,-40px,0);
}

/* trigger the float animation after 4s */
.with-slide-float:not(.with-slide-zoom) .slide:target .slide-gfx > *:first-child,
.with-slide-float:not(.with-slide-zoom) .slide:focus .slide-gfx > *:first-child,
.with-slide-float-hover:not(.with-slide-zoom) .slide .slide-gfx > *:first-child:hover {
  animation:                         css-slideshow-levitate 4s;
  animation-direction:               alternate;
  animation-fill-iteration-count:    infinite;
  animation-timing-function:         ease-in-out;
  animation-delay:                   2s;
}

/* longer delay for automatic version i.e. non-hover */
.with-slide-float:not(.with-slide-zoom) .slide:target .slide-gfx > *:first-child,
.with-slide-float:not(.with-slide-zoom) .slide:focus .slide-gfx > *:first-child {
  animation-delay:                   4s;
}

/* Vebdor animations for the float */
@keyframes css-slideshow-levitate {
  from { transform: translate(0,-40px); transform: translate3D(0,-40px,0); }
  to   { transform: translate(0,-20px); transform: translate3D(0,-20px,0); }
}

/** --------------------------------------------------------------------------
 * Add-on module : ground shadow (optional)
 * ------------------------------------------------------------------------ */

.with-shadow .slide .slide-gfx:before {
  content: '';
  background: url('slide-shadow.svg') no-repeat center center;
  position: absolute;
  bottom: -10px;
  left: -20px;
  right: -20px;
  height: 20px;
  z-index: -1;
  opacity: 0.7;
}

.with-shadow.with-slide-float .slide .slide-gfx:before,
.with-shadow.with-slide-float-hover .slide .slide-gfx:before {
  transition-property:        opacity;
  transition-duration:        2s;
  transition-timing-function: ease-in-out;
}

.with-shadow.with-slide-float .slide .slide-gfx:before {
  transition-delay: 2s;
}

.with-shadow.with-slide-float .slide:target .slide-gfx:before,
.with-shadow.with-slide-float .slide:focus .slide-gfx:before,
.with-shadow.with-slide-float .slide:last-child .slide-gfx:before,
.with-shadow.with-slide-float-hover .slide .slide-gfx:hover:before {
  opacity: 0.1;
  animation:                      css-slideshow-shadow 4s;
  animation-delay:                4s;
  animation-direction:            alternate;
  animation-fill-iteration-count: infinite;
  animation-timing-function:      ease-in-out;
}

.with-shadow.with-slide-float-hover .slide .slide-gfx:hover:before {
  animation-delay: 2s;
}

/* Vebdor animations for the float */
@keyframes css-slideshow-shadow { from { opacity: 0.1; } to { opacity: 0.7; } }

simple screenshot of implemented example


реализованный пример (v0.2)

http://codelamp.co.uk/css-slideshow/v0.2/

обратите внимание: скачок nav i.e. круговые точки полагаются на небольшой бит JavaScript. Остальное - чистый CSS.


предыдущая версия

Как я уже сказал, для усовершенствования этой системы потребовалось довольно много времени. Для тех, кому может быть интересно, вот моя (последняя) версия 0.1 — их было много раньше;) Это заняло несколько иной подход и включало как визуальные, так и интерактивные движущиеся части. В конце концов я отказался от него, потому что он занимался большей обработкой браузера, и поэтому был намного более неуклюжим; что-то, что эта сплошная демонстрация цвета не раскрывает.

http://jsfiddle.net/3cyP8/7/