Под катом вы узнаете о том, как быстро и легко оформить взаимодействие с 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

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

Комментарии (66)


  1. indrauolles
    18.02.2016 18:11
    +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. Вот он-то и будет захламленным, но поскольку код мы пишем не там, то нам будет всё равно.


    1. Paul_King
      18.02.2016 18:34
      -3

      Да, со сборщиками все куда проще, но ведь размер итоговой html страницы тоже имеет значение.
      Вы привели хороший пример, но вариант с iframe мне тоже кажется интересным. Если он работает, то почему бы и нет?)


      1. ImKremen
        18.02.2016 18:50
        +3

        Имхо, количество запросов критичнее размера страницы.


        1. Paul_King
          18.02.2016 20:56

          Зависит от самой страницы.
          К примеру, на странице с лентой новостей много повторяющихся иконок (поделиться, комментировать, количество просмотров и т.д. ). В случае с object, мы получим 1 запрос на каждую картинку и гораздо меньше итогового кода.
          К сожалению, для стилизации SVG нет идеального метода. Приходится выбирать меньшее из зол.


          1. Aux
            19.02.2016 02:19
            +1

            Ничего плохого в object нет, картинки-то вставляем через img, видео через videoи никто не жалуется.


  1. lifestyle
    18.02.2016 19:18
    -2

    > text-decoration сразу несколько значений (причем это работает уже очень давно)

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

    > новые свойства только в Firefox и, частично, в Safari
    Okay


    1. Paul_King
      18.02.2016 21:17

      Вы не совсем поняли.

      • несколько значений в text-decoration — работает давно
      • text-decoration-color и text-decoration-style — только в Firefox и, частично, в Safari


  1. Razunter
    18.02.2016 19:44
    +1

    Какая-то подборка вредных советов…
    1) Text-decoration ладно, может быть полезным, но раз пока нет поддержки в Chromium, то и говорить не о чём.
    2) За плавную прокрутку карать. Бесит везде, где появляется.
    3) С новой строкой куда проще будет

    .break:after {
    content: '';
    display: block;
    }
    


    1. Paul_King
      18.02.2016 21:38
      +2

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


  1. romy4
    18.02.2016 19:58

    а в HTML лезть не хочется (или невозможно),

    но всё равно без того, что бы лезть в html не получится сделать. В примере нужно слово обрамляется классом, что не сделаешь без того, чтобы не лезть в html.


    1. Paul_King
      18.02.2016 20:58

      Разумеется!
      Подразумевалось, что у нас есть возможность обратиться к нужному месту через селектор.


      1. firya
        19.02.2016 12:17
        +2

        Если есть возможность обрамить текст тегом, то всегда будет проще поставить br
        У указанного метода есть одна неприятная особенность, работает он только с inline элементами, перенести inline-block таким способом нельзя


  1. lain8dono
    19.02.2016 00:23

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

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

    var styles = document.querySelectorAll('svg style')
    for (var i = 0, l = styles.length; i < l; i++) {
        document.head.appendChild(styles[i])
    }


    1. Paul_King
      19.02.2016 07:42

      Селектором svg styles мы.не сможем обратиться к стилям в файле SVG, если он вставлен через <img/>. Иначе мы бы просто обращались к нужным элементам в SVG через наш основной CSS.

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


  1. syno
    19.02.2016 02:36
    +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. oshibka404
      19.02.2016 03:54
      +1

      А картинки так не будут дважды с сервера запрашиваться? Один раз — как src тега img, второй — через $.get.
      И если одна картинка на странице встречается 10 раз, то 10 одинаковых запросов на сервер уйдёт?


    1. Paul_King
      19.02.2016 07:47

      Да, нам тоже так пришлось делать в свое время. И это решение нам очень не нравилось из-за своей грузности (было заметро, что новые SVG-шки загружались секунды через 2-3 после загрузки страницы).


  1. funnybanana
    19.02.2016 04:48
    -1

    и не слово про

    transition
    


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

    P.S что-то маловато frontend-хитростей…


    1. Paul_King
      19.02.2016 09:39

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

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

      блок появится без анимации. Он изначально будет непрозрачным.


  1. exeto
    21.02.2016 13:22
    +1

    Интересный вариант подключения SVG-иконок предложил Владимир Кузнецов.


  1. MechanisM
    22.02.2016 00:15
    +1

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