Существует очень популярный трюк CSS, состоящий в использовании сочетания сплошных и прозрачных границ для элемента шириной 0 и высотой 0, чтобы имитировать треугольник. Если вы еще не знаете технику, вы можете найти больше информации о ней в следующих ресурсах:
- CSS Triangle на CSS-хитрости
- CSS Треугольник Дэвида Уолша
- Генератор CSS Треугольник
- CSS Arrow Пожалуйста! (генератор треугольников CSS)
Несмотря на то, что эта техника имеет некоторые странные особенности, она на самом деле хорошо справляется со своей задачей и имеет преимущество в том, что она очень совместима с широким спектром браузеров, которые мы должны поддерживать.
Дело в том, что я никогда полностью не помню, как использовать этот маленький кусочек кода. Какие границы должны быть прозрачными? Какой из них должен быть твердым? Я просто не могу понять это, и держу пари, что для многих из вас это тоже самое. Так что, как правило, вы хотели бы автоматизировать это с помощью Sass.
Вероятно, существует столько же CSSin-треугольников, сколько Sass-разработчиков. Что если я покажу вам свой собственный миксин для работы с CSS-треугольниками / стрелками в CSS?
Что нам нужно?
Прежде чем копаться в коде, было бы неплохо проверить, что нам нужно, чтобы сделать треугольник из CSS. Первое: направление . Нам нужно определить направление для нашей стрелки: top
, right
, bottom
или left
. Кроме того, как насчет должности ? Например, на 1,5em сверху, 100% слева . Также мы можем определить цвет и, возможно, размер , хотя эти два аргумента могут иметь значения по умолчанию.
Итак, в конце концов, наш миксин — это короткий путь для нас, чтобы сказать: « Сгенерируйте треугольник, указывающий на это направление, в этом месте, в этом цвете и в следующих измерениях» . Звучит хорошо, правда?
Обратите внимание, что во избежание использования дополнительной разметки я люблю использовать псевдоэлементы для треугольников. Например:
.element { /* Container of some kind */ &::before { /* Including triangle mixin */ } }
Используя наш инструментарий
На прошлой неделе я написал о некоторых функциях и миксинах, чтобы запустить ваш проект . Если вы еще не читали эту статью, продолжайте. Я буду ждать.
Хорошо, готово? Что если мы повторно использовали некоторые наши миксины, чтобы сделать этот треугольный миксин как можно более острым и чистым? Например, мы могли бы использовать mixin size()
чтобы нам не приходилось определять ширину и высоту. Мы также могли бы поддерживать согласованный API для позиционирования и использовать миксин absolute()
(подробнее об этом миксине здесь ).
Чтобы иметь весь код в этом посте, позвольте мне также включить здесь 3 миксина:
// Sizing stuff @mixin size($width, $height: $width) { width: $width; height: $height; } // Positioning stuff @mixin position($position, $args) { @each $o in top right bottom left { $i: index($args, $o); @if $i and $i + 1 <;= length($args) and type-of(nth($args, $i + 1)) == number { #{$o}: nth($args, $i + 1); } } position: $position; } // Absolutely positioning stuff @mixin absolute($args) { @include position(absolute, $args); }
Также нам понадобится функция opposite-direction()
; либо тот, что от Compass, либо тот, который я написал в моем предыдущем посте.
Сборка Миксин
Теперь, когда у нас есть все необходимые утилиты, давайте приступим к созданию нашего треугольного миксина. Во-первых, давайте создадим скелет миксина.
Подпись Mixin
Вот как будет выглядеть наш миксин:
@mixin triangle( $direction, $position, $color: currentColor, $size: 1em ) { /* Mixin content */ }
Как направление, так и положение являются необязательными параметрами. Между тем цвет по умолчанию будет соответствовать значению CSS currentColor
, которое всегда лучше, чем возврат к черному. Что касается размера, так как все треугольники в моем проекте были нормализованы, чтобы иметь одинаковый размер, я сделал размер необязательным параметром, но не стесняйтесь делать его необязательным, если хотите.
Для тех из вас, кто любит очень формальный синтаксис подписи, вот как это будет выглядеть:
triangle(string $direction, list $position, color $color: currentColor, number $size: 1em)
Mixin Core
Давайте сначала разберемся с самой простой частью: ядром миксина. Другими словами, размеры и положение треугольника. Мы позаботимся о границах позже.
@mixin triangle($direction, $position, $color: currentcolor, $size: 1em) { @include absolute($position); @include size(0); content: ''; z-index: 2; /* Border stuff */ }
Довольно чисто, не правда ли? Вот что он делает:
- Позиционирует элемент благодаря mixin
absolute()
. - Делает элемент
0
шириной,0
высотой. - В случае, если это псевдоэлемент (почти всегда), он появляется с использованием свойства
content
. - Использует
z-index
чтобы убедиться, что он находится над слоем по умолчанию (я полагаю, вы можете удалить это, если хотите).
Границы
Хорошо, мы сделали самую легкую часть. Главным образом потому, что у нас были собственные миксины, облегчающие боль. Теперь нам нужно разобраться со всеми границами. Это где opposite-direction
вступает в игру. Используя пример, давайте вспомним, как это работает. Учтите, что мы хотим определить треугольник, указывающий направо :
- Правая граница не должна быть определена
- Левая граница должна быть цветной
- Верхняя граница должна быть прозрачной
- Нижняя граница должна быть прозрачной
Это приводит нас к следующему коду:
@mixin triangle($direction, $position, $color: currentcolor, $size: 1em) { /* Core stuff */ border-#{opposite-position($direction)}: $size * 1.5 solid $color; $perpendicular-border: $size solid transparent; @if $direction == top or $direction == bottom { border-left: $perpendicular-border; border-right: $perpendicular-border; } @else if $direction == right or $direction == left { border-bottom: $perpendicular-border; border-top: $perpendicular-border; } }
Сначала мы определяем противоположную границу. Для этого мы используем функцию opposite-direction()
. В нашем предыдущем примере opposite-direction
вернулось бы left
, следовательно, свойство было бы border-left
. Что касается размера, мне пришло в голову, что он выглядит лучше, если немного увеличить размер этой границы. Но это довольно произвольно, поэтому не стесняйтесь обновлять его, если оно вам не нравится.
Наконец, мы определяем перпендикулярные границы. Если направление top
или bottom
, эти границы имеют border-left
и border-right
а если направление left
или right
, перпендикулярные границы имеют border-top
border-bottom
. Обе границы должны быть прозрачными.
Обработка ошибок
Как всегда, мы не должны забывать обрабатывать ошибки в нашем миксине. Чтобы сделать миксин простым, я убедился, что направление в порядке. То есть это должно быть одно из 4 общих смещений. Я считаю, что важно сделать эту проверку, потому что можно решить передать угол (например, 42deg
), как это делается для функции linear-gradient()
.
@mixin triangle($direction, $position, $color: currentcolor, $size: 1em) { @if not index(top right bottom left, $direction) { @warn "Direction must be one of `top`, `right`, `bottom` or `left`; currently `#{$direction}`."; } @else { /* Mixin content */ } }
Обратите внимание, как мы используем функцию index()
чтобы увидеть, является ли направление одним из 4 смещений, вместо того, чтобы вручную проверять каждое с помощью ==
.
В среде Sass 3.3 мы могли бы сделать нашу функцию чуть более пуленепробиваемой, если сначала $direction: to-lower-case($direction)
: $direction: to-lower-case($direction)
. Это предотвратит ошибку в случае, если направление не полностью в нижнем регистре. Детали имеют значение.
Я совсем недавно писал о том, как поддерживать несколько версий Sass одновременно. Я настоятельно рекомендую вам прочитать статью, но в основном это будет выглядеть так:
@mixin triangle($direction, $position, $color: currentcolor, $size: 1em) { $direction: if(function-exists("to-lower-case") == true, to-lower-case($direction), $direction); @if not index(top right bottom left, $direction) { @warn "Direction must be one of `top`, `right`, `bottom` or `left`; currently `#{$direction}`."; } @else { /* Mixin content */ } }
Что касается позиции, то это должна быть работа mixin position()
для обработки ошибок, а не mixin triangle()
. Что касается цвета и размера, мы, вероятно, могли бы проверить тип данных, но я чувствовал, что проверки позиции было достаточно для этой демонстрации.
Использование и пример
Использовать его довольно просто. Но помните, поскольку элемент, который включает в себя треугольный миксин, позиционируется абсолютно, его родитель должен иметь position: relative
.
/** * 1. Enable absolute positioning for pseudo-element * 2. Using a pseudo-element to generate the arrow * 3. Same as @include triangle(bottom,top 100% left 1em, $color); */ .tooltip { $color: #3498db; position: relative; /* 1 */ background: $color; padding: .5em; border-radius: .15em; color: white; text-align: center; &::before { /* 2 */ @include triangle( $direction : bottom, $position : top 100% left 1em, $color : $color ); /* 3 */ } }
А вот живое демо для вас, чтобы поиграть:
Последние мысли
В конце концов, миксин довольно прост, тебе не кажется? Он не только повторно использует существующие миксины, чтобы избежать необходимости кодировать надоедливые вещи вручную, но также использует умные функции, такие как opposite-direction
и директива @if
чтобы сделать наш код максимально сухим .
Я надеюсь тебе это понравится. Дайте нам знать, если вы найдете это полезным.