Статьи

Ультимат Миксин с длинной тенью

Вы знаете тенденцию дизайна теней , верно? Хотя я даже не уверен, что это тенденция больше, все движется так быстро … В любом случае, длинные тени были и / или все еще являются модной дизайнерской уловкой, чтобы придать некоторый акцент некоторому тексту или элементу.

В CSS нет простого способа создать длинную тень. В конце концов, либо вы используете какой-либо формат на основе изображений (фактическое изображение, SVG …), либо вы полагаетесь на text-shadow и box-shadow . Последние варианты лучше, потому что они не что иное, как CSS, который может быть очень хорошо обработан браузером.

Проблема в том, что писать — это боль. Чтобы добиться чистого эффекта длинной тени, вы должны построить цепочку из примерно 50 теней, слегка сдвигая значения по одному шагу за раз, возможно, и цвет … Вполне непрактично. Обычно это тот тип вещей, который вы хотите автоматизировать с помощью Sass или любого другого инструмента, плавающего на вашей лодке.

Действительно, было много попыток сделать длинную теневую смесь. Среди решений, которые я видел, я заметил проблемы, в том числе:

  • нет способа определить направление;
  • нет способа определить количество теней;
  • работает только для text-shadow ;
  • слишком сложный

Хорошо пристегните ремни, потому что я нашел то, что я смею называть чистым решением . Я построил независимую от свойств функцию длинной тени длиной ~ 15 строк, которая принимает направление (а также несколько других аргументов).

API

Поскольку мы хотим, чтобы наш инструмент работал со свойствами box-shadow и text-shadow , мы на самом деле создадим не миксины, как говорится в заголовке статьи, а фактически функцию . Тогда вы сможете использовать его так:

 .foo { box-shadow: long-shadow($args...); } .bar { text-shadow: long-shadow($args...); } 

Действительно, тени от ячеек и тени текста почти идентичны, за исключением того, что у теней ящиков есть параметр размытия, который мы не будем использовать. Обратите внимание, что Internet Explorer 10+ поддерживает размытие и для текстовых теней … Правдивая история.

Нашей функции нужна пара вещей для работы:

  • направление, аналогичное linear-gradient поэтому ключевое слово или угол (в deg , rad , grad или turn );
  • длина;
  • цвет;
  • следует ли отметить, что тень должна исчезнуть (по умолчанию установлено значение false ); это либо логическое значение (где true означает переход от прозрачного к прозрачному), либо цвет к исчезающему;
  • количество теней для вычисления (по умолчанию 100 ).
  

Построение функции

Теперь давайте начнем с этой функции. Первое, что мы должны сделать, - это преобразовать $direction в угол, если это ключевое слово (например, to right , 90deg ). Делать это очень просто; нам нужна только карта конверсии.

 $conversion-map: ( to top: 180deg, to top right: 135deg, to right top: 135deg, to right: 90deg, to bottom right: 45deg, to right bottom: 45deg, to bottom: 0deg, to bottom left: 315deg, to left bottom: 315deg, to left: 270deg, to left top: 225deg, to top left: 225deg ); @if map-has-key($conversion-map, $direction) { $direction: map-get($conversion-map, $direction); } 

На данный момент остается сделать только одну вещь (да, уже!): Итерацию от 1 до $shadow-count , каждый раз вычисляя новую тень.

 // ... $shadows: (); @for $i from 1 through $shadow-count { // ... $shadow: ...; $shadows: append($shadows, $shadow, 'comma'); } @return $shadows; 

Теперь нам нужно вычислить $shadow . Сначала я думал, что это будет боль, но это тригонометрия. Нам нужно только вычислить sin угла для смещения x и cos угла для смещения y. Затем мы умножаем оба на длину длинной тени, деленную на общее количество теней, умноженное на текущий индекс $i .

 $x: sin(0deg + $direction) * ($i * $length / $shadow-count); $y: cos(0deg + $direction) * ($i * $length / $shadow-count); 

Вы можете удивиться, почему мы добавляем $direction (угол) к 0 0deg . На самом деле, это умный способ приведения второго значения в единицу первого. В этом случае, если $direction выражено в градиентах, радианах или поворотах, оно автоматически преобразуется в эквивалент в градусах.

Что касается цвета, это немного сложнее. В зависимости от значения $fade у нас есть три варианта:

  • если $fade равен false , то цвет равен $color ;
  • если $fade имеет значение true , то мы изменяем $color с $color на прозрачный;
  • если $fade - это цвет, то мы изменяем $color с $color на $fade .

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

 // If `$fade` is `false` $current-color: $color; // If `$fade` is a color @if type-of($fade) == 'color' { $current-color: mix($fade, $color, ($i / $shadow-count * 100); // If `$fade` is `true` } @else if $fade { $current-color: rgba($color, 1 - $i / $shadow-count); } 

... или как один вкладыш:

 $current-color: if(not $fade, $color, if(type-of($fade) == 'color', mix($fade, $color, ($i / $shadow-count * 100)), rgba($color, 1 - $i / $shadow-count))); 

Итак, на данный момент наша тень (которая будет добавлена ​​в список теней):

 $shadow: $x $y 0 $current-color; 

Вся функция

 @function long-shadow($direction, $length, $color, $fade: false, $shadow-count: 100) { $shadows: (); $conversion-map: ( to top: 180deg, to top right: 135deg, to right top: 135deg, to right: 90deg, to bottom right: 45deg, to right bottom: 45deg, to bottom: 0deg, to bottom left: 315deg, to left bottom: 315deg, to left: 270deg, to left top: 225deg, to top left: 225deg ); @if map-has-key($conversion-map, $direction) { $direction: map-get($conversion-map, $direction); } @for $i from 1 through $shadow-count { $current-step: ($i * $length / $shadow-count); $current-color: if(not $fade, $color, if(type-of($fade) == 'color', mix($fade, $color, ($i / $shadow-count * 100)), rgba($color, 1 - $i / $shadow-count))); $shadows: append($shadows, (sin(0deg + $direction) * $current-step) (cos(0deg + $direction) * $current-step) 0 $current-color, 'comma'); } @return $shadows; } 

Примеры

 .foo { text-shadow: long-shadow( // Shadow should have an angle of 42 degrees $direction: 42deg, // Shadow should be contain within a 100x100 box $length: 100px, // Shadow should start this color $color: #16a085, // To finish this color $fade: #1abc9c ); } 

длинная тень пример 1

 .bar { box-shadow: long-shadow( // Shadow should go to bottom right (45deg) $direction: to left, // With a length of 15em $length: 15em, // From this color $color: #2980b9, // To this color $fade: #e67e22 ); } 

длинная тень пример 2

 .baz { box-shadow: long-shadow( // Shadow should have an angle of 25deg $direction: -125deg, // Spread on 120px $length: 120px, // From this color $color: #8e44ad, // To transparent $fade: true, // With only 10 shadows $shadow-count: 10 ) } 

длинная тень пример 3

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

Вот и все мои друзья! Я надеюсь, вам понравится как сила, так и простота этого подхода. Не стесняйтесь предлагать какие-либо улучшения и обязательно посмотрите код на CodePen!