CSS лучше, чем JS

CSS

оригинал:The State of CSS Reflections

Примечание: чтобы облегчить понимание читателя, в этой статье используется свободный перевод, а не дословный перевод, во-вторых, исходный текст очень длинный, и автор также предлагает решение, совместимое с браузером.Этот перевод сосредоточен на введении.box-reflexЭффект атрибута не объясняет проблемы совместимости.Заинтересованные читатели могут нажать на исходный текст, чтобы прочитать, спасибо~

Напоследок: перевод не из легких, перевод просит Звезду://github.com/qiud...

Недавно я былCodePenЯ нашел чистую реализацию CSS на заборе с градиентным отражением и эффектом 3D-вращения.Его метод реализации: использование 10<div>Элемент создает 10 полос сетки, затем дублирует всю<div>элемент и создайте маску градиента, чтобы сформировать эффект градиента, действующий как отражение забора.

Это похоже на почесывание затылка за правым ухом пальцами левой ноги (Переводчик понимает: значение выражения должно состоять в том, чтобы использовать сложный способ обращения с вещью, которую на самом деле можно достичь простым способом.)! Не говоря уже о том, что этот способ градиентной маскировки просто не работает для неодноцветных фонов. Разве нет лучшего способа, основанного на CSS?

Ответ — да, у нас есть лучший способ добиться этого эффекта! Но, к сожалению, совместимость этого способа недостаточно хороша, если мы не хотим использоватьcanvas, но также надеемся, что он будет совместим со всеми основными браузерами, описанный выше метод, несомненно, является лучшим.

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

Кодовая база

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

Сначала мы создаем.loaderобертка и содержит 10.barэлемент

<div class='loader'>
  <div class='bar'></div>
  <!-- 继续创建9条 -->
</div>

Помимо непосредственного написания HTML, мы также можем использовать препроцессоры, такие какHaml:

.loader
  - 10.times do
  .bar

Мы начинаем эти элементы из промежуточного положения в области просмотра. Обычно мы все используемtop: 50%центрировать, но если мы используемbottom: 50%Позже будет удобнее.

div {
  position: absolute;
  bottom: 50%; left: 50%;
}

Мы определяем ширину и высоту этих стержней забора и задаем фон:

$bar-w: 1.25em;
$bar-h: 5 * $bar-w;

.bar {
  width: $bar-w; height: $bar-h;
  background: currentColor;
}

Мы хотим, чтобы нижний край сетки перекрывал горизонтальную центральную ось окна просмотра, установив параметрbottom: 50%Этот эффект был достигнут.

В этот момент все наши полосы сетки сложены вместе, их левый край совпадает с продольной центральной осью окна просмотра, а нижний край перекрывается с горизонтальной центральной осью,Посмотреть онлайн:

позиционирующий забор

Нам нужно расположить эти заборы так, чтобы левый край первого забора и правый край последнего забора находились на одинаковом расстоянии от продольной центральной оси, которое всегда равно количеству заборов ($n) умножить на ширину полосы ($bar-w) половину полученного значения. В начальной демонстрации использовались обычныеCSS, теперь мы используемSassчтобы упростить количество кода,Посмотреть здесь:

Переводчик: Специальное напоминание, ширина полосы$bar-wсерединаСтоляр, а не минус, во избежание двусмысленности используйте его позже$bar_wзаменять

Это означает, что, начиная с позиций всех полос сетки, нам нужно переместить первую полосу сетки влево.0.5 * $n * $bar_w. слеваxОтрицательное направление оси, а это значит, что впереди требуется отрицательный знак, поэтому первая сеткаmargin-leftзначение-.5 * $n * $bar_w.

Позиция второй сетки состоит в том, чтобы переместить ширину сетки вправо от позиции первой сетки, затем ееmargin-leftзначение должно быть-.5 * $n * $bar_w + $bar_w;

Аналогично, третья сеткаmargin-leftзначение-.5 * $n * $bar_w + 2 * $bar_w;

Затем последняя сеткаmargin-leftто есть:-.5 * $n * $bar-w + ($n - 1) * $bar-w.

Как показано ниже:Посмотреть онлайн

Мы выражаем это в коде как:

$n: 10;

@for $i from 0 to $n {
  .bar:nth-child(#{$i + 1}) {
  margin-left: ($i - .5 * $n) * $bar-w;
  }
}

мы устанавливаем ихbox-shadow, поэтому мы можем четко видеть конец одного бара и начало следующего:

покрасить забор

Цвет фона забора начинается с крайнего левого угла.темно-синий(#1e3f57) крайний правыйсветло-синий(#63a6c1), что звучит какSassизmix()что делает функция.mix()Первый параметр — светло-синий, второй параметр — темно-синий, а третий параметр (называемый относительным весом в %) — это количество светло-голубого, включенное в окончательный результат смешивания.

Для первой сетки количество голубого должно быть0% - 0%, поэтому окончательный результат будет только темно-синим;

Точно так же для последней полосы количество голубого должно быть100% -100%, композиция фонового цвета светло-голубая;

Для остальных баров нам нужно сделать медиану равномерно распределенной. Предположим, у нас есть$nполосы сетки, первый0%, последний есть100%, то нам нужно разбить их на$n - 1равноудаленные промежутки. Как показано ниже:

Как правило, число$iОтносительный вес стержней сетки:$i * 100% / ($n - 1), мы добавляем следующий код:

$c: #63a6c1 #1e3f57; // 1st = light 2nd = dark

@for $i from 0 to $n {
  // list of mix() arguments for current bar
  $args: append($c, $i * 100% / ($n - 1));

  .bar:nth-child(#{$i + 1}) {
  background: mix($args...);
  }
}

Теперь заборы выглядят так же, как и в оригинальной демонстрации:Посмотреть онлайн

-webkit-box-reflect

box-reflectвсе ещенестандартные свойства, который еще не поддерживается многими основными браузерами, к счастью, он доступен вwebkitОн отлично работает в браузере, просто добавьте личные свойства браузера.

Давайте посмотрим, как это работает, его значение состоит из трех частей:

-webkit-box-reflect:none | <direction> <offset>? <mask-box-image>?
  • <direction>: направление отражения, которое может бытьbelow, left, above, rightлюбое значение в
  • <offset>: расстояние между отражением и исходным изображением, значение может быть фиксированным значением в пикселях или в процентах.
  • <mask-box-image>: Установите эффект маски отражения, который может быть фоновым изображением или градиентным изображением.

Следующая интерактивная демонстрация иллюстрирует это (вы можете щелкнуть, чтобы изменить направление, смещение и т. д. отражения):

прямое интервьюdemoИграй сам!

В нашем случае первое, что приходит на ум, это.loaderдобавьте это в:

.loader {
  -webkit-box-reflect: below 0 linear-gradient(rgba(#fff, 0), rgba(#fff, .7));
}

Во-вторых, мы также должны дать.loaderУстановите размер, потому что содержащиеся в нем заборы в настоящее время абсолютно позиционированы..loaderФактический размер0px X 0px. Мы определяем его ширину как сумму всех ширин забора и его высоту как высоту забора:

$loader-w: $n * $bar-w;

.loader {
  width: $loader-w; height: $bar-h;
  box-shadow: 0 0 0 1px red;
}

После добавления приведенного выше кода вы увидите следующий эффект в браузере webkit:Посмотреть онлайн

Мы уже можем видеть границы загрузчика и некоторые отражения, но они уже не в правильном положении. Нам нужно отцентрировать загрузчик слева, совместив нижние части ограждений с нижними частями их родительских элементов:

.loader { margin-left: -.5 * $loader-w; }

.bar { bottom: 0; }

Это решает проблему позиционирования, и эффект следующий:

// Здесь опущен ряд схем совместимости с Firefox: element()+svg mask  …

анимация

Анимация, изначально реализованная в CodePen, была очень простой, просто 3D-турникет:

@keyframes bar {
  0% {
  transform: rotate(-.5turn) rotateX(-1turn);
  }
  75%, 100% { transform: none; }
}

Применить анимацию ко всем заборам:

animation: bar 3s cubic-bezier(.81, .04, .4, .7) infinite;

Затем добавьте разные задержки для каждого такта:

animation-delay: $i*50ms;

Поскольку мы 3D-турникет, нам также необходимоloaderдобавить элементperspectiveАтрибуты:.

.loader {
  perspective: 62.5em;
}

но это толькоwebkitиспользовать в браузере-webkit-box-reflectдействует когда. Достигнут конечный эффект:Посмотреть онлайн

Последние мысли

Забудьте, этот абзац не нужно переводить!

По поводу того, что автор-webkit-box-reflectа такжеelement()+mask(svgизmaskтег) для решения проблемы отражения в кроссбраузерной реализации, не влияя на наше пониманиеbox-reflectОтлично, заинтересованные читатели могут посмотреть оригинальный текст, спасибо~