Как часто вам приходилось решать дифференциальное уравнение или находить интеграл после окончания учебы? Думаю, нечасто, если, конечно, вы не ученый. Но есть дисциплины, теоретические знания по которым могут внезапно пригодиться нам в работе, даже если эта работа напрямую не связана с наукой. Одна из таких дисциплин — геометрия.
В этой статье я хочу рассказать о задаче, решить которую мне помогли геометрические формулы. И поскольку я занимаюсь разработкой интерфейсов, то речь пойдет о верстке вот такого всплывающего сообщения.
На первый взгляд, ничего сложного. Быстро набрасываем основные стили, добавляем скругления и тень, а указатель в виде треугульника делаем с помощью псевдоэлемента и широко известной техники. Проверяем результат:
> http://codepen.io/belyan/pen/vymwXe
Все хорошо, вот только треугольник тоже должен быть с тенью. Но если мы добавим тень к нашему псевдоэлементу, то ничего не получится: тень будет квадратной.
Получается, что данный способ подходит только для создания простых треугольников, без тени и обводки.
Попробуем применить другую, чуть менее известную технику создания треугольников в CSS. Опять воспользуемся бордерами, только сделаем треугольник в левом верхнем углу, добавим элементу тень и сдвинем ее в тот же угол с помощью отрицательных значений. Теперь повернем элемент на 45 градусов по часовой стрелке — и получим треугольник с тенью.
> http://codepen.io/belyan/pen/ObmYQa
Результат выглядит уже лучше, но не идеально. Если присмотреться, то видно, что на макете треугольник чуть ниже, чем у нас. И мы не сможем это исправить, поскольку наш треугольник всегда будет оставаться прямоугольным. Мы можем добавить ему скругление, и даже эмулировать обводку с помощью внутренней тени, но мы не можем изменить значение верхнего угла.
Для создания непрямоугольного треугольника воспользуемся более сложным способом. Суть его в том, что мы создаем квадрат, поворачиваем на 45 градусов и наклоняем на нужный угол, чтобы получить ромб, и затем скрываем его нижнюю часть. В результате получаем равнобедренный треугольник любых размеров, которому мы можем добавить тень, границу и скругление.
Сложность заключается в том, что приходится вручную подбирать размеры квадрата и угол наклона, пока не добьемся нужного вида. Поэтому многие этот способ и не используют. Так давайте напишем миксин, который будет делать все вычисления за нас!
Пишем миксин
Далее я буду использовать препроцессор LESS, но данный миксин можно легко переписать и на SCSS.
Возьмем в качестве иллюстрации вот такой треугольник и зададим в качестве начальных параметров его размеры — основание b
и высоту h
.
Начнем вычисления с нахождения стороны a
. Поскольку высота равнобедренного треугольника делит его основание пополам, то боковую сторону a
можно найти по теореме Пифагора:
@base: 100px;
@height: 100px;
@side: sqrt(@base * @base / 4 + @height * @height); // про штаны, надеюсь, все помнят ;)
Зная значения всех сторон, мы можем найти боковой угол alpha
. Вспоминаем, что синус угла есть отношение противолежащего катета к гипотенузе. Противолежащий катет у нас h
, а гипотенуза — a
. Таким образом:
@alpha: asin(@height / @side); // результат будет в радианах!
Теперь необходимо вычислить угол наклона для трансформации нашего квадрата после поворота на 45 градусов. Для этого дорисуем прямоугольный треугольник, основание которого совпадает с нашим.
Теперь наглядно видно, что угол наклона beta
будет равен разности между боковым углом alpha
и углом поворота.
@beta: convert(@alpha, deg) - 45deg; // не забываем перевести радианы обратно в градусы
Последнее значение, которое нам необходимо вычислить, — это боковая сторона квадрата до его трансформации. Для этого воспользуемся косинусом угла. Угол наклона нам известен, а прилежащим катетом будет являться сторона a
. Таким образом, боковую сторону можно вычислить по формуле:
@size: @side * cos(@beta);
Теперь мы знаем исходные размеры квадрата, а также углы поворота и наклона, для трансформации его в ромб. Добавляем необходимые стили и скрываем нижнюю половинку ромба с помощью overflow: hidden
, в результате получаем равнобедренный треугольник заданных размеров. Миксин готов.
> http://codepen.io/belyan/pen/wozWXE
Применяем его к нашему всплывающему сообщению и получаем наконец желаемый результат. :)
> http://codepen.io/belyan/pen/LbyKEd
Хочу добавить, что с помощью этого же миксина мы можем создавать и равносторонние треугольники, поскольку они являются частным случаем равнобедренных. В этом случае нам достаточно будет задать только основание треугольника, а его высоту можно легко вычислить по формуле:
@height: @base * sin(60deg);
.
Также можно добавить в миксин возможность задания направления вершины треугольника: top
, left
, right
, bottom
. Я не стал этого делать в статье, поскольку объем кода существенно увеличился бы. Тем же, кому интересна эта тема, предлагаю взглянуть на расширенную версию данного миксина. Там же вы найдете миксины и для других геометрических фигур, таких как круг, овал, крест, звезда и пр.
> http://codepen.io/belyan/pen/Lpqdmx
Надеюсь, вам было интересно. Спасибо за внимание!
Комментарии (19)
claygod
29.11.2016 15:12+2По поводу картинки учебника в начале статьи. Мне довелось учиться по учебнику Колмогорова 6-8 класс, и это был замечательный, очень удобный учебник, благодаря которому знания геометрии давались легко:
CaptainCrocus
29.11.2016 16:46+1Мы занимались в нагрузку по Александрову (стереометрия) и Скопецу.
А вот Колмогорова «Алгебра и математический анализ» (именно так, а не «начала») я найти не могу. А он был.
Не встречали?
Eldhenn
29.11.2016 16:07+16А потом мы спрашиваем, откуда берутся (вернее, куда уходят) гигабайты и гигагерцы…
belyan
29.11.2016 17:32А как бы вы решили эту задачу, картинкой?
Eldhenn
30.11.2016 10:33+2А почему, собственно, нет? Для паршивого треугольничка в хинте мы используем одну алгебраическую и две тригонометрических функции, выполняем фиг знает сколько арифметических действий, да ещё и вертим картинку (через шейдеры, я полагаю).
belyan
30.11.2016 15:11Вы понимаете как работают CSS-препроцессоры? Все вычисления происходят на этапе компиляции. На размер CSS-кода это не влияет. И уж тем более любая картинка будет занимать гораздо больше "гигабайт", не говоря уже о том, что делать тени с помощью изображения, мягко говоря, не круто.
PTM
29.11.2016 16:46судя по рисунку у вас равносторонний треугольник=>
a=sqrt( sqr(0.5*b)+sqr(h))
тк h=b, то
a=b*sqrt(1.25)
customtema
30.11.2016 11:33Думаю, нечасто, если, конечно, вы не ученый.
Не ученый, программист. Часто. Геометрия, алгебра, анализ, вышки, русский язык :)
Docent86
04.12.2016 14:54Фурье преобразования, дискретное преобразование Фурье, Гауссова функция, матричные преобразования, переходы в разные системы координат. Пока учился даже не подозревал для чего всё это может пригодиться, теперь приходится всё заново повторять.
monochromer
04.12.2016 14:54Еще можно использовать css-фильтр drop-shadow. Тень будет повторять форму объекта со всеми выступающими его частями.
Пример на js binbelyan
04.12.2016 15:10Согласен, за этим способом будущее. Жаль, что IE поддерживает фильтры, только начиная с версии Edge 13.
lookid
И как успехи?