company_banner

Несколько неочевидных frontend-хитростей

  • Tutorial
Под катом вы узнаете о том, как быстро и легко оформить взаимодействие с SVG-иконками, добавить плавный скролл с помощью одного CSS-правила, анимировать появление новых элементов на странице, переносить текст на новую строку с помощью CSS и о новых способах оформления декоративной линии текста.

wg css html

Оформление декоративной линии текста (text-decoration-style, text-decoration-color)


В Firefox и Safari уже довольно давно появились дополнительные возможности для оформления декоративной линии, которая добавляется к тексту с помощью свойства text-decoration.

К примеру, можно задавать свойству text-decoration сразу несколько значений (причем это работает уже очень давно):
multiple text-decoration
.multiple {
  text-decoration: underline overline;
}

Можно задавать цвет для оформления текста:
text-decoration-color
.color {
  text-decoration-color: blue;
}

А также стиль линии:
text-decoration-style
.dashed {
  text-decoration-style: dashed;
}
.dotted {
  text-decoration-style: dotted;
}
.wavy {
  text-decoration-style: wavy;
}

Учтите, что в данный момент работают новые свойства только в Firefox и, частично, в Safari. Посмотреть рабочий пример можно здесь

Плавная прокрутка страницы на CSS (scroll-behaviour)


Малоподдерживаемое, но очень полезное свойство scroll-behaviour позволит нам одной строкой сделать скролл на странице плавным. Работает как при прокрутке в нужное место при переходе по якорям, так и при прокрутке страницы JS-ом.

body {
  scroll-behavior: smooth;
}

Свойство может принимать 3 основных значения:
  • smooth — плавная прокрутка;
  • instant — мгновенная прокрутка;
  • auto — на усмотрение браузера.

Когда нибудь (надеюсь, совсем скоро) нам не придется больше писать функции для плавной прокрутки на JS или подключать сторонние библиотеки.

Если плавная прокрутка страницы на вашем сайте не является чем-то критичным, смело используйте это свойство. Вы получите плавный скролл при переходе по якорям с помощью всего одного CSS-правила как минимум, в Firefox .
Пример

Анимация появления элемента (быстро и легко)


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

simple fade-in animation
Как это часто делали раньше:
1) на сервер посылаетcя запрос;
2) после загрузки ответа данные добавляются в скрытый на странице блок;
3) блоку присваивается класс, в котором прописана анимация его появление (либо (о, ужас!) блок анимируется JS-ом).

Так вот, последний пункт можно считать избыточным, ведь у нас есть старое доброе CSS-свойство animation. По умолчанию анимация срабатывает при загрузке страницы либо при изменении DOM-дерева (а именно при добавлении элементу класса с анимацией или самого элемента). Поэтому, важно не хранить незаполненные блоки в DOM, а добавлять их динамически в контейнеры по мере загрузки.
@keyframes fade-in {
    0% {
        opacity: 0;
    }
    100% {
        opacity: 1;
    }
}

.content {
  animation: fade-in .4s ease;
}

Вот и все, что нужно для создания простой анимации появления. Плюсы такого подхода очевидны:
  • Прописав @keyframes один раз, можно использовать их в любом месте CSS для добавления типовой анимации всем нужным элементам;
  • Обращения к DOM в JS будут сведены к минимуму, что при большом количестве элементов или итераций поможет снизить нагрузку на страницу.

Минус у данного подхода только один: новые элементы не могут храниться в DOM и ждать, пока мы наполним их контентом. Их разметку придется хранить на стороне JS…

Изучить рабочий пример можно здесь.

Разрыв строки на CSS


Если в определенном месте на странице вам нужно добавить перенос строки, а в HTML лезть не хочется (или невозможно), на помощь придет CSS. Первое, что приходит в голову — добавить псевдоэлемент с тегом <br> внутри:

.break:after {
    content: '<br />';
}

К сожалению (а может, и к счастью), добавлять теги в псевдоэлементы, нельзя. Но выход есть!

.break:after {
    content: '\A'; //код переноса строки
    white-space: pre; //заставляет браузер отображать текст с учётом всех пробелов и переносов, добавленных в код
}

Маленький пример.

SVG с интерактивными элементами


Если вам когда-нибудь приходилось оформлять взаимодействие с SVG-элементами, вы знаете, что сделать это не так-то просто. Чтобы обращаться в CSS к отдельным SVG-элементам, приходится добавлять на страницу не тег <img/>, а код всего SVG-изображения целиком. Это делает HTML-код ужасно громоздким. В результате нам приходится жертвовать размером страницы и лаконичностью кода ради визуальных эффектов.

Но! У нас есть неплохая альтернатива — прописывать все стили взаимодействия прямо в SVG:

<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" >
    <defs>
        <style type="text/css">
            rect {
                fill: blue;
            }
            rect:hover {
                fill: orange;
            }
        </style>
    </defs>

    <rect />
    <rect />
    <rect />
    <rect />
</svg>

Казалось бы, если мы прописали стили в самом изображении, то они должны отрабатывать при добавлении SVG как обычного <img />! Однако, не все так просто. Добавленные таким образом стили все равно работать не будут. Но мы можем сделать ход конем и добавить SVG на страницу с помощью <iframe> или <object>:
<iframe src="icon.svg"></iframe>
или
<object type="image/svg+xml" data="icon.svg"></object>

svg iframe animation

Возможно, это не самое красивое решение, но оно явно лучше, чем захламленная SVG-кодом страница. Если вы знаете более красивый способ, пожалуйста, поделитесь им в комментариях!

UPD. Пользователь Large поделился классным решением, которое подробно описано здесь.
Еше одно интересное решение от пользователя exeto.

Кстати, при желании в SVG-файл можно добавить и CSS анимацию:
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" >
    <defs>
        <style type="text/css">
            @keyframes fill-change {
                0% {
                    fill: blue;
                }
                50% {
                    fill: orange;
                }
                100% {
                    fill: blue;
                }
            }
        
            rect {
                animation: 2s ease fill-change infinite;
                fill: blue;
            }
        </style>
    </defs>
    
    <rect />
    <rect />
    <rect />
    <rect />
    <path />
</svg>

svg css animation

Надеюсь, описанные здесь вещи показались вам интересными, а кому-то даже пригодятся на практике. До новых встреч!
Wargaming
89.04
Company
Share post

Comments 67

    +2
    Но мы можем сделать ход конем и добавить SVG на страницу с помощью iframe или object:

    Главное — смотреть, чтобы при этом этот SVG не порезался каким-нибудь АдБлокером
      +2
      Зачем iframe и object, если SVG можно вставлять напрямую в HTML?
        0
        А зачем писать CSS в отдельных файлах, если можно оформлять элементы прямо в HTML?)

        1. Мы делаем код красивее и лаконичнее.
        2. Отделяем струкруту документа от изображений.
          +6
          Не обязательно их "руками" вставлять, пусть это делается при сборке.
            +3
            Это понятно. Когда есть возможность, можно все автоматизировать. У нас на одном из проектов использовался js скрипт, который вытягивал исходный код SVG из тега <img /> и вставлял на страницу. Но, в любом случае, это идет во вред размеру страницы или производительности. Иногда это заметно, а иногда нет.
            Если вариант с iframe проще и он работает, то почему бы его не использовать?
              +4
              Вы хотите сказать, что iframe с SVG лучше по размеру или производительности, чем тот же SVG, вставленный в HTML?
                0
                iframe — нет, object — да.
                  0
                  Почему?
                    –1
                    Потому что

                    <object data="icon.svg" type="image/svg+xml"></object>

                    короче, чем

                    <iframe frameborder="0" src="icon.svg">
                    <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
                    <svg id="Layer_1" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 17 15" enable-background="new 0 0 17 15" xml:space="preserve">
                    <defs>
                    <rect x="3" y="5" width="5" height="4">
                    <rect x="9" y="5" width="5" height="4">
                    <rect x="3" y="10" width="5" height="4">
                    <rect x="9" y="10" width="5" height="4">
                    <path d="M11,0C9.9,0,9,0.9,9,2H8c0-1.1-0.9-2-2-2C4.9,0,4,0.9,4,2s0.9,2,2,2l2.5,0L11,4c1.1,0,2-0.9,2-2S12.1,0,11,0 z M7,3H6C5.4,3,5,2.6,5,2s0.4-1,1-1c0.6,0,1,0.4,1,1V3z M11,3h-1V2c0-0.5,0.4-1,1-1c0.5,0,1,0.5,1,1S11.5,3,11,3z">
                    </svg>
                    </iframe>
                      0
                      Но ведь лишний запрос на сервер, да и в SVG есть use, правда не уверен, что shadow dom позволяет для него CSS писать.
                        0
                        Если у нас много повторяющихся иконок на странице, мы сделаем только 1 запрос и сильно сократим код.
                          0
                          symbol и use вам помогут, если есть цсс анимации — тогда беда (обсуждали в предыдущих темах)
                            0
                            Можете написать подробнее или дать ссылку на пример?
                              +1
                              Определяете иконки в одном шаблоне через symbol, а потом многократно используете через use со своими стилями. вот тут писали больше подробнее и обсуждали проблему с анимациями (в коментариях).

                              А вообще, если вы используете джангу не только как жсон апи (что почти наверняка так) то вообще можете подключать иконки инлайном прямо в серверных шаблонах.
                                0
                                Тоже интересный вариант, хоть и не без недостатков (приходится загружать весь набор иконок на страницу, а он может быть довольно большим).
                                В любом случае, решение очень интересное, спасибо!
                                  +2
                                  Панацеи нет. Вот тут сделан обзор разных методов подключения свг. По поводу размера набора — можно разделить иконки на уникальные для страницы и общие для 90% страниц. Так что это не большая беда.
                                    +1
                                    Кстати symbol не особо и нужен, ибо можно просто создать группу (g) с id и юзать её.
                                      +1
                                      Это как с template — не нужно дополнительно скрывать и браузер не будет обрабатывать эту часть до использования use. А так конечно — можно использовать, просто будут дополнительные затраты. В случае с анимацией так и приходится делать.
                0
                Можно использовать веб-компоненты и не извращаться с отдельным js, вытягивающим код SVG. И с чего вы взяли, что SVG во внешнем файле это более легкое и производительное решение? В обоих случаях фетчится и рендерится XML, только в случае с внешним файлом вы еще получаете отдельный запрос, как минимум. А еще SVG можно вставлять в CSS, и LESS, к примеру, этот процесс умеет автоматизировать.
            +1
            Ну если одна иконка используется на странице N раз, то что ещё делать?
            –7
            HTML5 + CSS3

            .dotted {
            text-decoration-style: dotted;
            }
            .wavy {
            text-decoration-style: wavy;
            }

            Это жестоко. Нехватает только text-decoration: blink и text-decoration: marquee

            Учтите, что в данный момент работают новые свойства только в Firefox и, частично, в Safari.

            Надеюсь, описанные здесь вещи показались вам интересными, а кому-то даже пригодятся на практике.

            Надеюсь никому и никогда это не пригодится на практике.
              +3
              На многих сайтах есть псевдоссылки, оформленные с помощь border-bottom: dotted (например, ссылка "Написать комментарий на Хабре"). Разве не логичнее было бы оформить ее через text-decoration: underline dotted, раз уже это ссылка?

              text-decoration-style: wavy; тоже вполне может пригодится, дизайны-то бывают разные. В школе мы подчеркивали прилагательные волнистой линией, так почему в CSS у нас не должно быть возможности подчеркнуть прилагательное правильно?
                –7
                Потому что wavy переходит ту грань, где уже css начинает управлять дизайнером, а не дизайнер управляет css. То самое, от чего ушли в html, теперь возвращается в css (тег u, например).
                Вместо инструмента нам дают готовый кусочек дизайна и это считается нововведением. Отвратительно.
                  +6
                  Не совсем понимаю, почему text-decoration: underline или border-style: dotted — это инструмент, а text-decoration-style: wavy — кусочек дизайна, управляющий дизайнером?
                    +2
                    Вы не поделитесь своим инструментом для подчёркивания текста волнистой линией с помощью CSS?
                      –2
                      Давайте. Итак, я выступаю против "инструмента для подчёркивания текста волнистой линией", потому что он слишком специализирован.
                      Соответственно, чтобы расширить специализацию, можно предложить инструмент для подчеркивания текста любым паттерном. Хотя и это слишком узко. Мне бы подошел инструмент для рисования линейных паттернов на любом элементе.

                      Пожалуйста, вот он: border-image.

                      Уже сейчас вы можете рисовать волнистые, квадратнистые, и любые другие *истые линии на Ваше усмотрение (http://caniuse.com/#feat=border-image)

                      Или ждать пока большинство производителей даст вам возможность выбрать из… скольки? четырех? пяти? паттернов (http://caniuse.com/#search=text-decoration-style)

                      Встречный вопрос — как вы вообще посмели называть text-decoration-style инструментом для подчёркивания текста волнистой линией, если он поддерживается только в Firefox и Safari, в 18.53% браузерах по данным caniuse?
                        0
                        text-decoration-style это претендент на "инструмент для подчёркивания текста волнистой линией": https://drafts.csswg.org/css-text-decor-3/#text-decoration-style-property
                          –3
                          text-decoration-style это "претендент на инструмент для подчёркивания текста волнистой линией"

                          кавычку не там поставили.

                          В любом случае — я против и таких "претендентов", и таких "инструментов", по причинам выше.
                            0
                            Любые инструменты — это новые возможности, что, априори, здорово. А ЗЛО — это то, что из этого сотворит плохой дизайнер или разработчик. Можно и с помощью только одобренных вами инструментов создать люто убогий сайт.

                            Почему бы нам не получить в распоряжение стандартное средство для подчеркивания ошибок и прилагательных (wavy), глаголов (double), наречий и псевдоссылок (dashed)? Давайте тогда и обычный text-decoration уберем, и будем обычное подчеркивание оформлять только border-ом!
                              –1
                              Можно и с помощью только одобренных вами инструментов создать люто убогий сайт.

                              Можно создать люто убогий сайт вообще без CSS, так что ваш комментарий бесполезен чуть более чем полностью.

                              Почему бы нам не получить в распоряжение стандартное средство для подчеркивания ошибок и прилагательных (wavy), глаголов (double), наречий и псевдоссылок (dashed)?

                              Потому что настолько специализированные стандарты не работают. Вот не работают и все, никто это не будет использовать. Доказано Web 1.0 сайтами.
                                –1
                                Так что насчет text-decoration? Нужно его убрать или нет, по-вашему?
                                  –1
                                  оставить как legacy и не развивать.
                                    0
                                    border'ом не получится подчеркнуть многострочный текст.
                                      0
                                      Получится. но только с inline-block.
                          0
                          Внезапно. Спасибо, буду знать про товарища border-image.
                            +1
                            Имхо, text-decoration-style: wavy лучше чем border-image: url(wavy.png). Зачем нам картинки, если того же самого можно добиться CSS-ом?
                              +1
                              Наверное затем, что картинку можно кастомизировать, а это подчёркивание (пока что) нет. Более того — подобную картинку можно перегнать в base64. Я конечно понимаю, что 100 символов base64 картинки 5х5 пикселей больше 4х для "wavy", но с другой стороны инструмент намного гибче. Именно по-этому браузеры\стандарты имеют в последнее время развиваться в сторону теневого DOM, когда куча монолитных элементов могут разбиваться на тучу кастомизированных примитивов.

                              Так что я соглашусь — подобное подчёркивание — зло, но не столь серьёзное, как монолитные инпуты или селект. С другой стороны никто же не мешает забить на этот wavy и грузить ту же самую картинку.
                                0
                                Конечно, картинки нам дают намного больше гибкости. Но если подойдет стандартное подчеркивание, почему бы его не использовать?
                                Зачем нам тогда text-decoration: underline, если есть border-bottom?
                              +1
                              Они на разных уровнях находятся. border — под базовой линией. Так что неравная замена. wavy нужно для подчёркивания ошибок.
                      +1
                      scroll-behavior это не только CSS, но и JS:

                      window.scroll({ left, top, behavior });
                      window.scrollTo({ left, top, behavior });
                      window.scrollBy({ left, top, behavior });
                      element.scrollIntoView(ScrollOptions);

                      Для JS есть polyfill.
                        +1
                        В том-то и дело, что JS необязателен, если мы перематываем страницу к якорям стандартными средставами HTML (<a href="#some-block"></a>).

                        Если же мы все-таки используем js, нам не нужно заморачиваться описыванием работы анимации. Мы только указываем, куда прокрутить страницу.

                        За полифил спасибо, пригодится)
                        0
                        Меня, скорее всего, сейчас заминусуют, но всё-таки зачем этот пост?
                          +5
                          Думаю, чтобы узнать что-то новое. А наскольео эти знания полезны, решать вам.
                            0
                            Ничего нового не узнал. Пост первооткрывателейCSS3?
                              0
                              Могу только искренне позавидовать вашей эрудиции)
                          +2
                          С SVG можно поступить так:

                          • все svg помещаются в папку, с помощью плагина gulp-svg-sprite автоматически собирается спрайт
                          • в "разработческом" html подключаем спрайт и ссылаемся на его элементы (плагин gulp-file-include).
                            Например:

                            <div class="infographics_svg_sprite" style="display: none;">>@@include('../symbol/svg/sprite.symbol.svg')</div>
                            ...
                            <svg>
                            <use xlink:href="#britain_digits"/>
                            </svg>

                          • собираем итоговый html. Вот он-то и будет захламленным, но поскольку код мы пишем не там, то нам будет всё равно.
                            –3
                            Да, со сборщиками все куда проще, но ведь размер итоговой html страницы тоже имеет значение.
                            Вы привели хороший пример, но вариант с iframe мне тоже кажется интересным. Если он работает, то почему бы и нет?)
                              +3
                              Имхо, количество запросов критичнее размера страницы.
                                0
                                Зависит от самой страницы.
                                К примеру, на странице с лентой новостей много повторяющихся иконок (поделиться, комментировать, количество просмотров и т.д. ). В случае с object, мы получим 1 запрос на каждую картинку и гораздо меньше итогового кода.
                                К сожалению, для стилизации SVG нет идеального метода. Приходится выбирать меньшее из зол.
                                  +1
                                  Ничего плохого в object нет, картинки-то вставляем через img, видео через videoи никто не жалуется.
                            –2
                            > text-decoration сразу несколько значений (причем это работает уже очень давно)

                            But then
                            > text-decoration-color
                            > text-decoration-style
                            WTF! Неужели такое свойство «работает уже очень давно», а я верстал блядские псевдоссылки и нестандартное подчеркивание через border-bottom

                            > новые свойства только в Firefox и, частично, в Safari
                            Okay
                              0
                              Вы не совсем поняли.

                              • несколько значений в text-decoration — работает давно
                              • text-decoration-color и text-decoration-style — только в Firefox и, частично, в Safari
                              +1
                              Какая-то подборка вредных советов…
                              1) Text-decoration ладно, может быть полезным, но раз пока нет поддержки в Chromium, то и говорить не о чём.
                              2) За плавную прокрутку карать. Бесит везде, где появляется.
                              3) С новой строкой куда проще будет
                              .break:after {
                              content: '';
                              display: block;
                              }
                              

                                +2
                                1) ПОКА нет. Можете считать это анонсом. Знать, какие свойства появятся в будущем лишним не будет.
                                2) За что карать? Мне вот нравится понимать, куда проматывается страница по отношению к тому месту, где я находился.
                                3) C display: block могут быть проблемы, если рядом есть элементы с float. Мне кажется, растягивание псевдоэлемента на всю ширину может быть чревато другими последствиями. Правильнее будет просто перенести текст на новую строку, вместо того, чтобы разделять текст блоками.
                                0
                                а в HTML лезть не хочется (или невозможно),

                                но всё равно без того, что бы лезть в html не получится сделать. В примере нужно слово обрамляется классом, что не сделаешь без того, чтобы не лезть в html.
                                  0
                                  Разумеется!
                                  Подразумевалось, что у нас есть возможность обратиться к нужному месту через селектор.
                                    +2
                                    Если есть возможность обрамить текст тегом, то всегда будет проще поставить br
                                    У указанного метода есть одна неприятная особенность, работает он только с inline элементами, перенести inline-block таким способом нельзя
                                  0
                                  Но мы можем сделать ход конем и добавить SVG на страницу с помощью <iframe> или <object>

                                  А можно просто "полифил" сделать. Например вот так:

                                  var styles = document.querySelectorAll('svg style')
                                  for (var i = 0, l = styles.length; i < l; i++) {
                                      document.head.appendChild(styles[i])
                                  }
                                    0
                                    Селектором svg styles мы.не сможем обратиться к стилям в файле SVG, если он вставлен через <img/>. Иначе мы бы просто обращались к нужным элементам в SVG через наш основной CSS.

                                    Можно немного модернизировать ваш полифил, чтобы он сначала вытаскивал исходный код из удаленной SVG и заменял им <img/>, но это грузное решение.
                                    +1
                                    Я для SVG использую такой JQuery код:

                                    /*
                                         * Replace all SVG images with inline SVG
                                         */
                                            jQuery('img.svg').each(function(){
                                                var $img = jQuery(this);
                                                var imgID = $img.attr('id');
                                                var imgClass = $img.attr('class');
                                                var imgURL = $img.attr('src');
                                    
                                                jQuery.get(imgURL, function(data) {
                                                    // Get the SVG tag, ignore the rest
                                                    var $svg = jQuery(data).find('svg');
                                    
                                                    // Add replaced image's ID to the new SVG
                                                    if(typeof imgID !== 'undefined') {
                                                        $svg = $svg.attr('id', imgID);
                                                    }
                                                    // Add replaced image's classes to the new SVG
                                                    if(typeof imgClass !== 'undefined') {
                                                        $svg = $svg.attr('class', imgClass+' replaced-svg');
                                                    }
                                    
                                                    // Remove any invalid XML tags as per http://validator.w3.org
                                                    $svg = $svg.removeAttr('xmlns:a');
                                    
                                                    // Replace image with new SVG
                                                    $img.replaceWith($svg);
                                    
                                                }, 'xml');
                                    
                                            });

                                    Он автоматом заменит все

                                    <img class="name">

                                    на

                                    <svg>

                                    , которые можно видоизменить через css и класс .name
                                      +1
                                      А картинки так не будут дважды с сервера запрашиваться? Один раз — как src тега img, второй — через $.get.
                                      И если одна картинка на странице встречается 10 раз, то 10 одинаковых запросов на сервер уйдёт?
                                        0
                                        Да, нам тоже так пришлось делать в свое время. И это решение нам очень не нравилось из-за своей грузности (было заметро, что новые SVG-шки загружались секунды через 2-3 после загрузки страницы).
                                        –1
                                        и не слово про
                                        transition
                                        


                                        хотя тоже самое появление элемента с opacity:0; до opacity 1; делает так же плавно как и animation или fadeIn()...

                                        P.S что-то маловато frontend-хитростей…
                                          0
                                          Заставить элемент появляться плавно с помощью transition можно только меняя класс элемента JS-ом.
                                          Если вы напишете что-то вроде

                                          .block {
                                              transition: .3s ease all;
                                              opacity: 1;
                                          }

                                          блок появится без анимации. Он изначально будет непрозрачным.
                                          +1
                                          Интересный вариант подключения SVG-иконок предложил Владимир Кузнецов.
                                            +1
                                            Насчет декорирования ссылок, мне нравится как делают многие зарубежные новостные сайты.
                                            На одном из таких сайтов я выдернул код для примера и выложил на codepen.
                                            Ну согласитесь же, что некрасиво смотрится когда вот на картинках в примере видно как буква "у" сливается с линиями декорации.
                                              0
                                              Соглашусь, намного лучше.

                                            Only users with full accounts can post comments. Log in, please.