image


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


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


image


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


> http://codepen.io/belyan/pen/vymwXe


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


image


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


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


image


> http://codepen.io/belyan/pen/ObmYQa


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


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


image


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


Пишем миксин


Далее я буду использовать препроцессор LESS, но данный миксин можно легко переписать и на SCSS.


Возьмем в качестве иллюстрации вот такой треугольник и зададим в качестве начальных параметров его размеры — основание b и высоту h.


image


Начнем вычисления с нахождения стороны a. Поскольку высота равнобедренного треугольника делит его основание пополам, то боковую сторону a можно найти по теореме Пифагора:


@base: 100px;
@height: 100px;
@side: sqrt(@base * @base / 4 + @height * @height); // про штаны, надеюсь, все помнят ;)

Зная значения всех сторон, мы можем найти боковой угол alpha. Вспоминаем, что синус угла есть отношение противолежащего катета к гипотенузе. Противолежащий катет у нас h, а гипотенуза — a. Таким образом:


@alpha: asin(@height / @side); // результат будет в радианах!

Теперь необходимо вычислить угол наклона для трансформации нашего квадрата после поворота на 45 градусов. Для этого дорисуем прямоугольный треугольник, основание которого совпадает с нашим.


image


Теперь наглядно видно, что угол наклона 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)


  1. lookid
    29.11.2016 15:06

    И как успехи?


  1. claygod
    29.11.2016 15:12
    +2

    По поводу картинки учебника в начале статьи. Мне довелось учиться по учебнику Колмогорова 6-8 класс, и это был замечательный, очень удобный учебник, благодаря которому знания геометрии давались легко:

    image


    1. CaptainCrocus
      29.11.2016 16:46
      +1

      Мы занимались в нагрузку по Александрову (стереометрия) и Скопецу.
      А вот Колмогорова «Алгебра и математический анализ» (именно так, а не «начала») я найти не могу. А он был.
      Не встречали?


      1. Danov
        29.11.2016 18:06
        +1

        http://sheba.spb.ru/shkola/index.htm#alg


    1. GeMir
      29.11.2016 18:07

      У Атанасяна, помнится, тоже неплохой учебник был для 7–9 класса.


      1. sajtpro
        29.11.2016 23:29

        Атанасян для 10-10 класса то же есть. Уже стереометрия.


  1. Eldhenn
    29.11.2016 16:07
    +16

    А потом мы спрашиваем, откуда берутся (вернее, куда уходят) гигабайты и гигагерцы…


    1. belyan
      29.11.2016 17:32

      А как бы вы решили эту задачу, картинкой?


      1. Eldhenn
        30.11.2016 10:33
        +2

        А почему, собственно, нет? Для паршивого треугольничка в хинте мы используем одну алгебраическую и две тригонометрических функции, выполняем фиг знает сколько арифметических действий, да ещё и вертим картинку (через шейдеры, я полагаю).


        1. belyan
          30.11.2016 15:11

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


      1. sven47
        30.11.2016 14:51

        Просто отобразить картинку нарисованого треугольника не подойдет?


  1. PTM
    29.11.2016 16:46

    судя по рисунку у вас равносторонний треугольник=>
    a=sqrt( sqr(0.5*b)+sqr(h))
    тк h=b, то
    a=b*sqrt(1.25)


    1. belyan
      29.11.2016 17:30

      Если бы треугольник был равносторонним, то его высота была бы примерно 20 пикселей, по макету же высота составляет 10 пикселей. Поменяйте вот тут значение @arrow-height на @arrow-width * sin(60deg) и получите равносторонний треугольник.


      1. PTM
        30.11.2016 11:30

        Прошу прощения, следовало написать равнобедренный.


  1. customtema
    30.11.2016 11:33

    Думаю, нечасто, если, конечно, вы не ученый.


    Не ученый, программист. Часто. Геометрия, алгебра, анализ, вышки, русский язык :)


    1. GeMir
      30.11.2016 16:36

      Не учёный. Учитель (математики). Тоже, бывает, приходится.


  1. Docent86
    04.12.2016 14:54

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


  1. monochromer
    04.12.2016 14:54

    Еще можно использовать css-фильтр drop-shadow. Тень будет повторять форму объекта со всеми выступающими его частями.

    Пример на js bin


    1. belyan
      04.12.2016 15:10

      Согласен, за этим способом будущее. Жаль, что IE поддерживает фильтры, только начиная с версии Edge 13.