Русский
Русский
English
Статистика
Реклама

Css

Перевод О конфликтах Sass и сравнительно новых возможностей CSS

22.07.2020 16:08:14 | Автор: admin
Сравнительно недавно в CSS появилось много интересных возможностей, таких, как CSS-переменные и новые функции. Хотя всё это и может сильно упростить жизнь веб-дизайнерам, эти возможности способны неожиданными способами взаимодействовать с CSS-препроцессорами вроде Sass.



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

Ошибки


Если вы экспериментировали с CSS-функциями min() и max(), то, используя разные единицы измерения, могли столкнуться с сообщениями об ошибках, наподобие такой: Incompatible units: vh and em.


Сообщение об ошибке, возникающее при использовании различных единиц измерения в функциях min() и max()

Это сообщение выводится из-за того, что в Sass есть собственная функция min(). CSS-функция min(), в результате, игнорируется. Кроме того, Sass не может выполнять вычисления, используя единицы измерения, между которыми нет чётко зафиксированной взаимосвязи.

Например, взаимосвязь единиц измерения cm и in определена чётко, поэтому Sass может найти результат функции min(20in, 50cm) и не выдаёт ошибку в том случае, если чем-то подобным воспользоваться в коде.

То же самое происходит и с другими единицами измерения. Например, все угловые единицы измерения взаимосвязаны: 1turn, 1rad или 1grad всегда приводятся к одним и тем же значениям, выраженным в единицах измерения deg. То же самое справедливо, например, и в случае, когда 1s всегда равно 1000ms. 1kHz всегда равно 1000Hz, 1dppx всегда равно 96dpi, 1in всегда равно 96px. Именно поэтому Sass может преобразовывать друг в друга значения, выраженные в этих единицах измерения, и смешивать их в вычислениях, используемых в различных функциях, вроде собственной функции min().

Но всё идёт не так, когда между единицами измерения нет чёткой взаимосвязи (как, например, выше, у em и vh).

И такое происходит не только при использовании значений, выраженных в разных единицах измерения. Попытка использования функции calc() внутри min() тоже приводит к появлению ошибки. Если попробовать, в min(), поместить что-то вроде calc(20em + 7px), то выводится такая ошибка: calc(20em + 7px) is not a number for min.


Сообщение об ошибке, возникающее при попытке использования calc() внутри min()

Ещё одна проблема появляется в ситуации, когда пытаются использовать CSS-переменную или результат работы математических CSS-функций (вроде calc(), min(), max()) в CSS-фильтрах наподобие invert().

Вот сообщение об ошибке, которую можно увидеть в подобных обстоятельствах: $color: 'var(--p, 0.85) is not a color for invert


Использование var() в filter: invert() приводит к ошибке

То же самое происходит и с grayscale(): $color: calc(.2 + var(--d, .3)) is not a color for grayscale.


Использование calc() в filter: grayscale() приводит к ошибке

Конструкция filter: opacity() тоже подвержена подобным проблемам: $color: var(--p, 0.8) is not a color for opacity.


Использование var() в filter: opacity() приводит к ошибке

Но другие функции, используемые в filter, включая sepia(), blur(), drop-shadow(), brightness(), contrast() и hue-rotate(), работают с CSS-переменными совершенно нормально!

Оказалось, что причина этой проблемы похожа на ту, которой подвержены функции min() и max(). В Sass нет встроенных функций sepia(), blur(), drop-shadow(), brightness(), contrast(), hue-rotate(). Но там есть собственные функции grayscale(), invert() и opacity(). Первым аргументом этих функций является значение $color. Ошибка появляется из-за того, что при использовании проблемных конструкций такого аргумента Sass не находит.

По той же причине проблемы возникают и при использовании CSS-переменных, представляющих как минимум два hsl() или hsla()-значения.


Ошибка при использовании var() в color: hsl()

С другой стороны, без использования Sass конструкция color: hsl(9, var(--sl, 95%, 65%)) это совершенно правильная и совершенно нормально работающая CSS-конструкция.

То же самое справедливо и для таких функций, как rgb() и rgba():


Ошибка при использовании var() в color: rgba()

Кроме того, если импортировать Compass и попытаться использовать CSS-переменную внутри linear-gradient() или radial-gradient(), можно столкнуться с ещё одной ошибкой. Но, в то же время, в conic-gradient() переменными можно пользоваться без всяких проблем (конечно, если браузер эту функцию поддерживает).


Ошибка при использовании var() в background: linear-gradient()

Причина проблемы кроется в том, что в Compass есть собственные функции linear-gradient() и radial-gradient(), а вот функции conic-gradient() там никогда не было.

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

Вот засада!

Решение проблемы


Эту проблему можно решить, если вспомнить о том, что Sass чувствителен к регистру, а CSS нет.

Это означает, что можно написать что-то вроде Min(20em, 50vh) и Sass не распознает в этой конструкции свою собственную функцию min(). Никаких ошибок при этом выдано не будет. Эта конструкция будет представлять собой правильно сформированный CSS-код, который работает именно так, как ожидается. Аналогично, избавиться от проблем с другими функциями можно, нестандартным образом записывая их имена: HSL(), HSLA(), RGB(), RGBA(), Invert().

Если говорить о градиентах, то тут я обычно использую такую форму: linear-Gradient() и radial-Gradient(). Делаю я это из-за того, что такая запись близка к именам, используемым в SVG, но в данной ситуации сработает и любое другое подобное имя, включающее в себя хотя бы одну заглавную букву.

Зачем все эти сложности?


Почти каждый раз, когда я пишу в Твиттере что-нибудь про Sass, мне начинают читать лекции о том, что сейчас, когда есть CSS-переменные, Sass пользоваться уже не нужно. Я решила, что мне стоит на это ответить и объяснить причину моего несогласия с этой идеей.

Во-первых отмечу, что я считаю CSS-переменные чрезвычайно полезными, и то, что я пользовалась ими для решения множества задач последние три года. Но я полагаю, что необходимо помнить о том, что их использование сказывается на производительности. А поиск проблемы, возникшей в лабиринте вызовов calc(), может оказаться пренеприятнейшим занятием. Стандартные браузерные инструменты разработчика пока не очень хороши в этом деле. Я стараюсь не увлекаться использованием CSS переменных, чтобы не попадать в ситуации, в которых их минусы показывают себя сильнее, чем их плюсы.


Не так-то легко понять то, какими будут результаты вычисления этих выражений calc()

В целом, если переменная используется как константа, не изменяется от элемента к элементу, или от состояния к состоянию (а в подобных случаях CSS-переменные, определённо, использовать нужно), или если переменная не уменьшает объёма скомпилированного CSS-кода (решая проблему повторений, создаваемую префиксами), тогда я буду использовать Sass-переменную.

Во-вторых поддержка переменных всегда была довольно-таки незначительной причиной среди тех причин, по которым я использую Sass. Когда я начала пользоваться Sass, а было это во второй половине 2012 года, я сделала это, в основном, ради циклов. Ради той возможности, которой до сих пор нет в CSS. Хотя я перенесла некоторую логику, связанную с циклами, в препроцессор HTML (так как это уменьшает объём сгенерированного кода и позволяет избежать необходимости модифицировать и HTML, и CSS), я всё ещё использую циклы Sass во множестве случаев. Среди них генерирование списков значений, создание значений для настройки градиентов, создание списков точек при работе с функцией polygon(), создание списков трансформаций и так далее.

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

- let n = 12;while n--.item

Затем я бы создала переменную $n в Sass (и в этой переменной должно было бы быть то же значение, что и в HTML) и запустила бы с её использованием цикл, в котором сгенерировала бы трансформации, используемые для позиционирования каждого из элементов:

$n: 12;$ba: 360deg/$n;$d: 2em;.item {position: absolute;top: 50%; left: 50%;margin: -.5*$d;width: $d; height: $d;/* аккуратно оформим стили */@for $i from 0 to $n {&:nth-child(#{$i + 1}) {transform: rotate($i*$ba) translate(2*$d) rotate(-$i*$ba);&::before { content: '#{$i}' }}}}

Минус этого всего заключается в том, что мне пришлось бы менять значения и в Pug-коде, и в Sass-коде в том случае, если изменилось бы количество элементов. В коде, кроме того, появляется много повторений.


CSS-код, сгенерированный на основе вышеприведённого кода

Теперь я перешла к другому подходу. А именно, с помощью Pug я генерирую индексы в виде пользовательских свойств, а затем использую их при объявлении transform.

Вот код, который планируется обработать с помощью Pug:

- let n = 12;body(style=`--n: ${n}`)- for(let i = 0; i < n; i++).item(style=`--i: ${i}`)

Вот Sass-код:

$d: 2em;.item {position: absolute;top: 50%;left: 50%;margin: -.5*$d;width: $d;height: $d;/* аккуратно оформим стили */--az: calc(var(--i)*1turn/var(--n));transform: rotate(var(--az)) translate(2*$d) rotate(calc(-1*var(--az)));counter-reset: i var(--i);&::before { content: counter(i) }}

Здесь можно поэкспериментировать с этим кодом.


Элементы, сгенерированные и стилизованные с использованием циклов

Применение такого подхода значительно уменьшило объём CSS-кода, сгенерированного автоматически.


CSS-код, сгенерированный на основе вышеприведённого кода

Но если нужно создать что-то вроде радуги, без Sass-циклов не обойтись.

@function get-rainbow($n: 12, $sat: 90%, $lum: 65%) {$unit: 360/$n;$s-list: ();@for $i from 0 through $n {$s-list: $s-list, hsl($i*$unit, $sat, $lum)}@return $s-list}html { background: linear-gradient(90deg, get-rainbow()) }

Вот рабочий вариант этого примера.


Многоцветный фон

Конечно, это можно сгенерировать и средствами переменных Pug, но у такого подхода нет преимуществ перед динамической природой CSS-переменных, и он не позволит уменьшить объём кода, передаваемого браузеру. В результате мне нет смысла отказываться от того, к чему я привыкла.

Я много использую встроенные математические функции Sass (и Compass), такие, как тригонометрические функции. В наши дни подобные функции являются частью спецификации CSS, но их поддержка реализована пока не во всех браузерах. В Sass таких функций нет, но в Compass они есть, и именно поэтому мне часто приходится применять Compass.

И, конечно, я могу написать в Sass собственные функции такого рода. Я так делала в самом начале, до того, как в Compass появилась поддержка обратных тригонометрических функций. Мне эти функции очень нужны, поэтому я написала их сама, пользуясь рядами Тейлора. Но в наши дни эти функции есть в Compass. Они лучше и производительнее тех, которые я писала сама.

Математические функции очень важны для меня по той причине, что я программист, а не художник. Значения в моём CSS-коде обычно формируются на основе математических вычислений. Это не какие-то магические числа, или что-то такое, что играет чисто эстетическую роль. В качестве примера их использования можно привести генерирование списка правильных или квазиправильных многоугольников для clip-path. Подобное применяется, например, при создании чего-то вроде аватаров или стикеров, форма которых отличается от прямоугольной.

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


Фигура с тремя вершинами

Вот как выглядит соответствующий Sass-код:

@mixin reg-poly($n: 3) {$ba: 360deg/$n; // базовый угол$p: (); // список координат точек, изначально пустой@for $i from 0 to $n {$ca: $i*$ba; // текущий угол$x: 50%*(1 + cos($ca)); // координата x текущей точки$y: 50%*(1 + sin($ca)); // координата y текущей точки$p: $p, $x $y // добавление координат текущей точки к списку координат}clip-path: polygon($p) // установка списка точек в качестве значения clip-path}

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

Немного более продвинутая версия этого примера может включать в себя вращение многоугольника, реализованное путём добавления одного и того же смещения ($oa) к углу, соответствующему каждой вершине. Это можно видеть в следующем примере. Здесь генерируются звёзды, которые устроены похожим образом, но всегда имеют чётное количество вершин. При этом каждая вершина с нечётным индексом располагается на окружности, радиус которой меньше основной окружности ($f*50%).


Звезда

Можно наделать и таких интересных звёздочек.


Звёзды

Можно создавать стикеры с границами (border), созданными с использованием необычных шаблонов. В данном примере стикер создаётся из единственного HTML-элемента, а шаблон, используемый для настройки border, создаётся с применением clip-path, циклов и математических вычислений в Sass. На самом деле, вычислений тут довольно много.


Стикеры со сложными границами

Ещё один пример представлен созданием фона для карточек. Здесь, в цикле, с помощью оператора получения остатка от деления и экспоненциальных функций, создаётся фон с имитацией эффекта дизеринга.


Эффект дизеринга

Здесь тоже интенсивно используются CSS-переменные

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

К сожалению, в CSS, каким бы заманчивым это ни выглядело, нельзя поместить что-то вроде следующего кода:

input::-webkit-slider-runnable-track,input::-moz-range-track,input::-ms-track { /* общие стили */ }

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

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

input::-webkit-slider-runnable-track { /* общие стили */ }input::-moz-range-track { /* общие стили */ }input::-ms-track { /* общие стили */ }

Но это может привести к тому, что одни и те же стили появятся в коде три раза. А если нужно, скажем, поменять у track свойство background, это будет значить, что придётся редактировать стили в ::-webkit-slider-runnable-track, в ::-moz-range-track и в ::-ms-track.

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

@mixin track() { /* общие стили */ }input {&::-webkit-slider-runnable-track { @include track }&::-moz-range-track { @include track }&::-ms-track { @include track }}

Итоги


Главный вывод, который я могу сделать, получился таким: Sass в это то, без чего нам пока не обойтись.

Пользуетесь ли вы Sass?

Подробнее..

Перевод CSS и множественный фон

31.07.2020 18:06:20 | Автор: admin
CSS-свойство background это одно из самых часто используемых свойств. Но сообщество веб-разработчиков пока не слишком хорошо осведомлено о возможностях, которые даёт использование множественного фона. Здесь я собираюсь серьёзно поговорить о том, что может дать применение множественного фона, и о том, как использовать стандартные механизмы CSS на полную мощность.

В этом материале я подробно расскажу о свойстве background-image, приведу наглядные примеры совместного использования нескольких фоновых изображений элемента, рассмотрю сильные стороны такого подхода. Здесь будет много иллюстраций.



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

Введение


CSS-свойство background это сокращённое свойство, которое позволяет настраивать следующие обычные свойства элементов:

  • background-clip
  • background-color
  • background-image
  • background-origin
  • background-position
  • background-repeat
  • background-size
  • background-attachment

Здесь основное внимание мы уделим свойствам background-image, background-position и background-size.

Рассмотрим следующий пример:

.element {background: url(cool.jpg) top left/50px 50px no-repeat;}

Начальная позиция фонового изображения находится в верхнем левом углу элемента. Размер изображения составляет 50px * 50px. При настройке свойства background важно помнить о порядке следования свойств, задающих позицию и размер фонового изображения.


Путь к изображению, его позиция и его размер

На предыдущем рисунке за значениями, относящимися к настройке свойства background-position, идут значения свойства background-size. Если разместить эти значения в другом порядке, мы получим неправильно оформленный CSS-код. Например такой:

.element {/* Осторожно: неправильный CSS */background: url(cool.jpg) 50px 50px/top left no-repeat;}

Позиция фонового изображения


Для настройки области расположения фона, исходной позиции фонового изображения, используется свойство background-origin. Мне нравится та гибкость, которую даёт свойство background-position. Оно позволяет позиционировать фон элементов разными способами:

  • Ключевые слова (top, right, bottom, left, center).
  • Процентные значения. Например: 50%.
  • Значения, задающие некие расстояния. Например: 20px 2.5rem.
  • Значения, представляющие собой отступы от краёв элемента. Например: top 20px left 10px.


Система координат

Начало системы координат, используемой при позиционировании фоновых изображений, находится в левом верхнем углу элемента. Начальным значением свойства background-position является 0% 0%.

Стоит отметить то, что значение top left это то же самое, что и значение left top. Браузер достаточно интеллектуален для того чтобы определить то, какая часть этого значения относится к оси X, а какая к оси Y.


Конструкции вида top left и left top равнозначны

.element {background: url(cool.jpg) top left/50px 50px no-repeat;/* Это - то же самое, что и следующее */background: url(cool.jpg) left top/50px 50px no-repeat;}

Размер фонового изображения


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


Сначала идёт ширина, а потом высота

Если ширина и высота фонового изображения являются одинаковыми, это значит, что у нас нет необходимости указывать два значения для background-size. В такой ситуации достаточно указать одно значение.

Тут, кстати, нелишним будет упомянуть о том, что в спецификации CSS по этому поводу сказано следующее: Если указано лишь одно значение, то предполагается, что второе значение это auto. Но этот механизм в браузерах не реализован, хотя в будущем ситуация может измениться. Благодарю Илью Стрельцына за то, что привлёк моё внимание к этой детали.


Одно значение задаёт и ширину, и высоту

Теперь, когда мы поговорили об основах использования свойства background, давайте поговорим о том, как работать с несколькими фонами.

Множественный фон


В свойстве background может быть описан один слой фона, до сих пор мы видели именно такие описания, или несколько слоёв, свойства которых разделены запятой. Если размеры нескольких фоновых изображений одинаковы, одно из них полностью перекроет другие.

.element {background: url(cool.jpg) top left/50px 50px no-repeat,url(cool.jpg) center/50px 50px no-repeat;}



Использование нескольких фоновых изображений

На вышеприведённом рисунке у элемента есть два слоя фоновых изображений. Каждое из этих изображений позиционировано по-своему. Это простейший пример использования множественного фона. А теперь давайте рассмотрим более продвинутый пример.

Порядок наложения фоновых изображений друг на друга


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

.hero {min-height: 350px;background: url('table.jpg') center/cover no-repeat,url('konafa.svg') center/50px no-repeat;}

Здесь у нас имеется изображение стола (table.jpg) и изображение тарелки (konafa.svg). Как вы думаете, какое из этих фоновых изображений будет выведено первым? Изображение стола или изображение тарелки?


Элемент с двумя фоновыми изображениями

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

.hero {background: url('konafa.svg') center/50px no-repeat,url('table.jpg') center/cover no-repeat;}



Первый фон накладывается на второй

Как видите, фон, заданный первым, находится выше фона, заданного вторым.

Сплошные цвета


Предположим, нам, используя CSS-инструменты настройки фона элемента, нужно сформировать одноцветный фон. Как это сделать? Это, благодаря CSS-градиентам, совсем несложная задача. Дело в том, что если воспользоваться функцией linear-gradient с одинаковыми стоп-цветами, это приведёт к появлению сплошного цвета.

.hero {background: linear-gradient(#3c88Ec, #3c88Ec)}


Фон, созданный с помощью linear-gradient и одинаковых стоп-цветов

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

Сценарии использования и практические примеры


Затемнение фонового изображения


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

.hero {background: linear-gradient(rgba(0, 0, 0, 0.15), rgba(0, 0, 0, 0.15)),url("landscape.jpg") center/cover;}


Затемнённое фоновое изображение

Ещё интереснее то, что тот же метод можно использовать для тонирования фонового изображения элементов.

.hero {background: linear-gradient(135deg, rgba(177, 234, 77, 0.25), rgba(69, 149, 34, 0.25),url("landscape.jpg") center/cover;}


Тонированный фон

Рисование средствами CSS


Возможности использования CSS-градиентов для рисования поистине безграничны. В частности, речь идёт о градиентах, описываемых с помощью функций linear-gradient, radial-gradient и других. В этом простом примере мы разберёмся с тем, как, используя градиенты, нарисовать ноутбук.


Изображение ноутбука

Давайте разберём это изображение и подумаем о том, какие градиенты нам понадобятся.


Пластиковая рамка дисплея, LCD-дисплей, отражение, скруглённые края корпуса, корпус

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

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

:root {--case: linear-gradient(#222, #222);--case-size: 152px 103px;--display: linear-gradient(#fff, #fff);--display-size: 137px 87px;--reflection: linear-gradient(205deg, #fff, rgba(255, 255, 255, 0));--reflection-size: 78px 78px;--body: linear-gradient(#888, #888);--body-size: 182px 9px;--circle: radial-gradient(9px 9px at 5px 5.5px, #888 50%, transparent 50%);--circle-size: 10px 10px;}

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


Схематичное изображение ноутбука

Реализация отражения света от рамки дисплея ноутбука


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


Отражение света от рамки дисплея ноутбука

LCD-дисплей


Дисплей ноутбука выровнен по центру оси X, а по оси Y он расположен со сдвигом в 6 пикселей от начала координат.


Дисплей ноутбука

Рамка дисплея


Рамка находится ниже дисплея, она центрирована по оси X, по оси Y она расположена со смещением в 0px от начала координат.


Рамка дисплея

Корпус ноутбука


А это самый интересный элемент. Для начала, надо учесть то, что элемент, представляющий корпус ноутбука, является прямоугольником, и то, что корпус имеет скруглённые края. Это достигается благодаря использованию пары окружностей.


Корпус ноутбука

Готовый рисунок


:root {--case: linear-gradient(#222, #222);--case-size: 152px 103px;--case-pos: center 0;--display: linear-gradient(#fff, #fff);--display-size: 137px 87px;--display-pos: center 6px;--reflection: linear-gradient(205deg, #fff, rgba(255, 255, 255, 0));--reflection-size: 78px 78px;--reflection-pos: top right;--body: linear-gradient(#888, #888);--body-size: 182px 9px;--body-pos: center bottom;--circle: radial-gradient(9px 9px at 5px 5.5px, #888 50%, transparent 50%);--circle-size: 10px 10px;--circle-left-pos: left bottom;--circle-right-pos: right bottom;}.cool {width: 190px;height: 112px;background-image: var(--reflection), var(--display), var(--case), var(--circle), var(--circle), var(--body);background-size: var(--reflection-size), var(--display-size), var(--case-size), var(--circle-size), var(--circle-size), var(--body-size);background-position: var(--reflection-pos), var(--display-pos), var(--case-pos), var(--circle-left-pos), var(--circle-right-pos), var(--body-pos);background-repeat: no-repeat;/*outline: solid 1px;*/}

Вот CodePen-проект, с которым вы можете поэкспериментировать.

Смешивание нескольких фонов


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


Цветное изображение и вспомогательный слой чёрного цвета

Обратите внимание на то, что в следующем фрагменте CSS-кода используется свойство background-blend-mode: color. Именно оно и позволяет достичь нужного эффекта

.hero {background: linear-gradient(#000, #000),url("landscape.jpg") center/cover;background-blend-mode: color;}


Обесцвеченное изображение

Пользуетесь ли вы множественными фонами в CSS?

Подробнее..

Перевод Технологии фронтенд-разработки, на которые вы, возможно, не обратили внимания

07.08.2020 16:22:19 | Автор: admin
Хочешь жить умей вертеться. Это про работу фронтенд-программиста. Для того чтобы успешно справляться со своими обязанностями, такому специалисту приходится решать массу задач и необходимо обладать множеством способностей. Очень важно, кроме того, не забывать о главной цели, ради которой разрабатывают сайты. А именно, о том, что сайты должны помогать людям упрощать решение их повседневных задач.



В этом материале я собираюсь рассказать о различных аспектах веб-разработки, о которых стоит знать любому программисту соответствующего профиля. Я, если это возможно, буду приводить ссылки на материалы, демонстрирующие примеры применения соответствующих возможностей и рекомендации по их правильному использованию. Здесь я буду ориентироваться на реализацию тех или иных механизмов в Angular, React и Vue.

Пользовательский интерфейс


Макет страницы


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

Существует множество CSS-фреймворков. Возможно, среди них вы обнаружите именно тот, который вам идеально подойдёт. Самый знаменитый из них это Bootstrap и, благодаря новым возможностям CSS-препроцессоров, вы можете подвергнуть стили этого фреймворка глубокой настройке. В нём вы можете найти различные компоненты и элементы управления, последовательное использование которых позволит создавать единообразно оформленные сайты.

В настоящий момент вышел альфа-релиз 5 версии Bootstrap.

Если вы предпочитаете создавать наборы стилей для своих проектов самостоятельно (компоненты, отступы, контейнеры и так далее), можете обратить внимание на CSS Flexbox, сделав этот способ гибкого размещения элементов веб-страниц основой вашего собственного CSS-фреймворка.

CSS Grid использует другой подход к организации материалов веб-страниц, размещая их в сетке.

Отзывчивый дизайн


Отзывчивостью называют возможность сайта адаптировать своё содержимое к устройству, на котором его просматривают. Например, на смартфоне и на ноутбуке эта статья будет выглядеть по-разному.

Отзывчивость веб-приложения помогает ему правильно отображаться на разных экранах, улучшает читабельность контента и пользовательский опыт.

На MDN можно узнать о том, что медиазапросы используются в тех случаях, когда нужно применить разные CSS-стили для разных устройств (например, для принтера или монитора), а также с учётом конкретных характеристик и параметров устройства (например, для разного разрешения экрана или для разной ширины области просмотра браузера).

CSS-медиазапросы это мощное средство поддержки отзывчивого дизайна.

Их можно использовать вместе с уже упомянутыми CSS Flexbox или CSS Grid. Если вы предпочитаете пользоваться CSS-фреймворками, то эти фреймворки обычно уже реализуют соответствующие возможности. При таком подходе для создания отзывчивых страниц достаточно добавить к элементам соответствующие классы.

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

Однородные компоненты и элементы управления


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

Если вы хотите использовать для разработки своих проектов существующие фреймворки и библиотеки, Angular, React или Vue, то вот несколько примеров библиотек стилей, реализующих принципы Material Design, рассчитанных на эти инструменты:

  • Angular. Библиотека Angular Material, в которой можно найти мощные компоненты и полный CDK.
  • React. Принципы Material Design реализованы в веб-компонентах библиотеки Material UI.
  • Vue. Здесь к нашим услугам Vuetify реализация Material Design, предназначенная для Vue-проектов.

Проверка форм и обработка ошибок


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

  • Angular. Так как Angular это полноценный фреймворк, он даёт в наше распоряжение специальный API, направленный на валидацию форм.
  • React. Вероятно, в React-проектах для проверки форм чаще всего используется библиотека React Hook Form.
  • Vue. Название соответствующей библиотеки для Vue, vuelidate, построено на интересной игре слов.

Пользовательский опыт


Использование асинхронных механизмов


Загрузка данных в приложение или сохранение данных могут занимать миллисекунды, секунды или даже минуты. Именно поэтому важно сообщать пользователю о подобных операциях с помощью соответствующих индикаторов и не блокировать при этом работу пользователя с проектом.

В решении этих задач нам помогут JavaScript-механизмы, вроде промисов, и браузерные API наподобие Fetch.

Поддержка устаревших браузеров (полифиллы)


Мир фронтенд-разработки развивается очень быстро. То же самое можно сказать и о браузерах. Но разные люди пользуются различными браузерами и разными их версиями. Поэтому, чтобы обеспечить правильную работу своего кода на всех применяемых платформах, разработчику нужно заботиться о совместимости. Например, старая версия IE не поддерживает те же возможности JS и CSS, которые поддерживает последняя версия Google Chrome.

Для обеспечения правильной работы проекта в старых браузерах применяются полифиллы. Они достаточно хорошо описаны в этом материале: Полифилл (polyfill, polyfiller) это фрагмент кода (или подключаемый модуль), который предоставляет реализацию технологии, которую вы, разработчик, ожидаете найти в числе стандартных возможностей браузера.

Для того чтобы узнать, поддерживается ли некое CSS-правило, или некая JS-функция в конкретной версии браузера, загляните на сайт Can I Use.

Если говорить о решении вопросов браузерной поддержки в Angular, React и Vue, то дело обстоит так:

  • Angular. В документации к Angular есть особый раздел, посвящённый браузерной поддержке.
  • React. Проекты, создаваемые с помощью Create React App, поддерживают, как и ReactDOM, браузеры, начиная с IE 9. Эта поддержка основана на использовании полифиллов.
  • Vue. Здесь особенности поддержки устаревших браузеров описаны в документации к CLI.

Локализация и интернационализация


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

Локализация (l10n, localization) это, по определению W3C, адаптация содержания продукта, программы или документа к языковым соответствиям, культурным и другим требованиям определённого целевого рынка.

Интернационализация (i18n, internationalization) это, если опираться на материалы W3C, создание и развитие содержания продукта, программы или документации, позволяющее производить лёгкую локализацию для целевых рынков, различающихся по культуре, региону или языку.

Обе эти концепции взаимосвязаны, они могут быть реализованы разными способами. Сюда относятся, например, следующие технические приёмы:

  • Использование на сайте выпадающего списка с перечнем языков, поддерживаемых проектом.
  • Доступ к сведениям о географическом местоположении пользователя (с помощью браузерного API Geolocation) и адаптация веб-сайта в соответствии с полученными данными.
  • Указание сведений о языке в URL. Например, это может выглядеть так: example.com?lang=en, или так: example.com/en, или даже так: en.example.com.

Теперь об этих концепциях в Angular, React и Vue.

  • Angular. Angular, повторюсь, это полноценный фреймворк, он даёт разработчику готовое решение.
  • React. Задачи интернационализации проектов можно решать с помощью популярной в React-среде библиотеки react-i18next.
  • Vue. В решении рассматриваемых нами задач очень хорошо показывает себя библиотека vue-i18n.

Доступность контента


Доступность (a11y, accessibility), это возможность сайта адаптироваться к нуждам пользователей с ограниченными возможностями.

О доступности веб-сайтов часто забывают. Для того чтобы сделать проект доступным для пользователей с ограниченными возможностями, может понадобиться пересмотреть используемый на нём подход к формированию пользовательского опыта, что иногда может потребовать глубокой переработки проекта. В любом случае, важно учитывать нужды всех пользователей, особенно принимая во внимание то, что даже небольшие изменения кода проекта способны значительно повысить удобство работы с сайтом для тех, кому тяжело пользоваться обычными сайтами.

В деле обеспечения доступности веб-проектов применимы различные технические приёмы. В их число входит следующее:

  • Использование атрибута изображений alt.
  • Применение ARIA-атрибутов для оформления описаний содержимого страниц сайта.
  • Поддержка возможности изменения размеров текста.
  • Наличие высококонтрастного режима.
  • Поддержка навигации по сайту с использованием клавиатуры, в частности, клавиши TAB и клавиш-стрелок.

В рамках проекта a11yproject.com проводится в жизнь идея стандартизации этих концепций. Эта инициатива достойна уважения! Основные JS-фреймворки и библиотеки тоже прилагают усилия к поддержке разработки доступных сайтов:

  • Angular. В документации к этому фреймворку есть особый раздел. Разработка доступных проектов поддерживается и на уровне Angular CDK.
  • React. Речь о доступности ведётся и в документации к библиотеке React. Существует и специальная библиотека react-a11y. Но эта библиотека больше не поддерживается, поэтому пользуйтесь ей с осторожностью и учитывайте то, что её планируется заменить на библиотеку react-axe.
  • Vue. Разрабатывать доступные проекты на Vue поможет плагин vue-a11y. При создании библиотеки vuetify тоже учтены соображения доступности.

Уведомления


Для того чтобы держать связь с посетителями вашего сайта, можно использовать браузерное API Notifications. С его помощью можно сообщать пользователям о том, что на сайте появилось что-то новое.

Загрузка и обработка данных


Единый источник достоверных данных


Средства для управления состоянием приложения, которые обрели популярность в 2015 году, в наши дни являются обязательным компонентом практически любого веб-проекта. Хотя в сфере управления состоянием приложений не всё однозначно, использование специализированных решений обычно является простым и эффективным методом централизованной обработки данных приложения. Все средства для управления состоянием основаны на паттерне Flux.


NgRx-реализация паттерна Flux (источник ngrx.io)

В этих средствах используются разные названия для одних и тех же сущностей. Например, то, что в NgRx называется selectors, в Vuex называется getters. То, что в Angular получило имя reducers, в Vue называется mutations.

Вот средства для управления состоянием приложений, используемые в Angular, React и Vue:

  • Angular. Реактивная система управления состоянием для Angular: NgRx.
  • React. Тут, конечно, применяется Redux.
  • Vue. Для управления состоянием Vue-приложений используется Vuex.

Загрузка данных


Существуют разные способы загрузки данных в приложения. Самый распространённый из них заключается в использовании HTTP-запросов, направленных к веб-API. В браузере имеется API Fetch, предназначенный для организации загрузки данных, но для основных фреймворков и библиотек разработаны собственные решения:

  • Angular. В документации к Angular рекомендуется использовать rxjs и подход, основанный на паттерне Observer (тут применяются наблюдаемые объекты или объекты класса Subject).
  • React. Документация React рекомендует для загрузки данных использовать API Fetch.
  • Vue. Сообщество Vue предпочитает использовать библиотеку Axios. Эта реализация механизма загрузки данных основана на промисах.

В разговоре о механизмах загрузки данных в веб-приложения стоит упомянуть о GraphQL. Эта технология изменила подход, используемый при загрузке данных во фронтенд-приложениях. При её применении Клиент определяет то, что ему нужно, используя язык запросов. Используя GraphQL мы можем получать из удалённых источников данных в точности то, что нам нужно, и ничего лишнего.

Вот реализации GraphQL для интересующих нас фронтенд-инструментов:


Локальное хранение данных


Локальное хранение данных это хранение данных на компьютере пользователя. Данные можно хранить с использованием куки-файлов, а так же с применением механизмов localStorage и sessionStorage.

Веб-воркеры


Веб-воркеры это технология, представленная новым браузерным API. Она даёт возможность фонового выполнения JavaScript-кода, снимая нагрузку с главного потока и не влияя на производительность кода веб-страницы.

Веб-воркеры применимы в Angular, React и Vue:

  • Angular. В документации к Angular есть особый раздел, посвящённый этому вопросу.
  • React. Существует особый React-хук, сведения о котором можно найти здесь.
  • Vue. Во Vue-приложениях веб-воркерами удобно пользоваться с применением библиотеки vue-worker.

Сеть и производительность


Размер бандла приложения


Рост рынка смартфонов стал причиной революции в мире веб-разработки. Теперь при создании веб-сайтов нам нужно, в первую очередь, учитывать нужды мобильных пользователей. Чем меньший объём данных придётся загружать мобильным устройствам при работе с веб-проектами тем лучше. В соответствии с графиком, показанным ниже, мобильное использование интернета обогнало настольное ещё в 2016 году.


Использование интернета в мире (источник broadbandsearch.net)

Это недвусмысленно говорит нам о том, как важны в наше время размеры бандлов веб-проектов. Размер загружаемых файлов должен быть, ради экономии ресурсов мобильных пользователей, как можно меньше. К нашему счастью, разработчики основных фронтенд-инструментов и дополнений к ним учитывают это, занимаясь развитием своих проектов. Уменьшение размеров бандлов приложений, кроме того, означает их более высокую производительность.

  • Angular. Бандлы Angular-приложений легко и удобно исследовать с помощью webpack-bundle-analyzer. Более того, CLI Angular даёт в наше распоряжение опцию stats-json, которая позволяет сформировать отчёт после сборки бандла.
  • React. В документации к Create React App есть страница, посвящённая анализу размеров бандлов.
  • Vue. Во Vue, как и в Angular, есть опция report, которая позволяет формировать отчёты по бандлам.

Сервис-воркеры и прогрессивные веб-приложения


Сервис-воркер это скрипт, который работает в веб-браузере и управляет кэшированием данных приложения. Это один из механизмов, используемых при превращении обычного веб-сайта в прогрессивное веб-приложение (PWA, Progressive Web Application). С PWA можно работать как с обычным сайтом, пользуясь HTTPS, но прогрессивные веб-приложения обладают некоторыми особыми возможностями. Среди таких возможностей, например, установка таких приложений на мобильные устройства без необходимости публикации их в специализированных магазинах приложений и поддержка работы приложений без доступа к интернету.

Пользоваться сервис-воркерами можно в Angular, React и Vue:

  • Angular. В Angular предусмотрены механизмы для использования сервис-воркеров.
  • React. Вот руководство по разработке PWA с помощью Create React App.
  • Vue. Возможность создания PWA во Vue поддерживается на уровне CLI.

Серверный рендеринг


Серверный рендеринг (SSR, Server-Side Rendering) это набор технологий, который кардинальным образом меняет ситуацию в сфере разработки приложений, основанных на Angular, React и Vue. При использовании SSR HTML-код формируется на сервере и отправляется в браузер. После этого осуществляется приведение статической HTML-разметки в рабочее состояние и на клиенте оказывается полностью готовое к использованию веб-приложение. При применении серверного рендеринга преследуют несколько целей:

  • Улучшение SEO сайтов.
  • Ускорение вывода сайтов в браузере.

Вот SSR-решения для исследуемых нами фронтенд-инструментов:


Генераторы статических сайтов


С ростом масштабов использования Jamstack генераторы статических сайтов (SSG, Static Site Generator) стали крайне востребованной технологией. Jamstack-приложение это разновидность веб-приложения, материалы которого готовы к визуализации средствами браузера и, по сути, не нуждаются в веб-сервере (эти материалы можно отдавать клиентам прямо с CDN). Подробности о таких сайтах можно найти, пройдя по вышеприведённой ссылке. Перечислим здесь лишь основные сильные стороны SSG:

  • Скорость: генераторы статических сайтов создают страницы сайтов во время сборки проекта, а не тогда, когда эти страницы запрашиваются клиентом.
  • Безопасность: применение SSG позволяет отказаться от систем управления контентом (CMS, Content Management System), которые часто оказываются целями хакерских атак.
  • Упрощение масштабирования: веб-проект при применении SSG представляет собой набор файлов, который можно передать клиенту откуда угодно. Это значительно упрощает хранение подобных файлов в CDN. В результате оказывается, что статические сайты очень хорошо масштабируются.
  • Упрощение процесса разработки: SSG-проектам не нужна серверная часть и база данных. Это облегчает труд разработчиков.

Существуют SSG-решения для Angular, React и Vue:


Среди других SSG-проектов можно отметить следующие: 11ty, Hugo, Jekyll.

Аналитика


Наблюдение за поведением пользователей и A/B-тестирование


Организация наблюдения за поведением пользователей на сайте это необязательно, но владение подобными данными вносит значительный вклад в совершенствование веб-проектов. Существует особый класс инструментов, направленных на сбор сведений о работе пользователей с сайтом. Эти инструменты позволяют разработчикам сайтов лучше учитывать нужды пользователей и, благодаря A/B-тестированию, помогают выбирать самые адекватные альтернативы. Речь идёт о возможностях сайтов, о поддерживаемых ими шаблонах поведения пользователей, о дизайне.

Вот некоторые решения, позволяющие организовать наблюдение за поведением пользователей и A/B-тестирование:

  • Google Analytics (GA). Существуют руководства по использованию GA в Angular, React и Vue.
  • Kameleoon. Это основанный на технологиях искусственного интеллекта фреймворк для персонализации и A/B-тестирования веб-проектов.

Анализ производительности веб-проектов


Сложно за один заход разработать высокопроизводительное веб-приложение. Но, например, приложение, которое оптимизировали с целью ускорения его загрузки, вызовет у пользователя больше положительных эмоций, чем его более медленная версия. Существуют различные проекты, анализирующие сайты и выдающие рекомендации по их совершенствованию. Например PageSpeed Insights от Google.

Среди инструментов разработчика Google Chrome можно найти весьма ценное средство для анализа производительности сайтов Lighthouse. Оно оценивает сайты по пяти критериям (производительность, доступность, использование лучших практик, SEO, PWA) используя 100-балльную шкалу. После анализа формируется отчёт с рекомендациями по улучшениям сайта.


Анализ сайта с помощью Lighthouse

Ещё одно средство анализа производительности, которое можно найти среди инструментов разработчика Chrome, это панель Coverage, позволяющая искать неиспользуемый JS и CSS-код. Исключив такой код из проекта, можно уменьшить размер его бандла. А это ускорит загрузку сайта, что будет особенно заметным на мобильных устройствах.

SEO


SEO, поисковая оптимизация, это то, чем надо заниматься ради повышения рейтинга сайта в поисковых системах, в таких, как Google, Bing, DuckDuckGo, да и во многих других. Хорошо оптимизированный сайт становится более заметным. На самом деле, это так важно, что в мире веб-разработки есть даже особая должность: SEO-специалист.

Если говорить о SEO в Angular, React и Vue, то получится следующее:

  • Angular. Вот интересная статья по поисковой оптимизации, которая применима к Angular- и к Angular Universal-проектам.
  • React. Вот материал об общих проблемах SEO в React-проектах. Вот статья об улучшении поисковой оптимизации React-приложений.
  • Vue. Вот подробная статья о поисковой оптимизации Vue-приложений.

Итоги


Я согласен с тем, что фронтенд-разработка это обширная и постоянно меняющаяся сфера знаний. На самом деле, если кто-то попытается стать универсальным разработчиком, всё знающим и умеющим, ему будет крайне сложно этого достичь, и на это ему потребуется очень много времени. При этом у каждого веб-проекта имеются собственные нужды и приоритеты. Именно поэтому необходимо определиться с самым важным в начале работы над проектом. Это позволит не распыляться, отобрав и изучив лишь самое нужное, и спланировать архитектуру проекта так, чтобы она соответствовала бы его целям.

Какие свежие технологии фронтенд-разработки кажутся вам самыми перспективными?

Подробнее..

Перевод 6 мощных возможностей CSS, которые позволяют обойтись без JavaScript

08.08.2020 16:12:48 | Автор: admin
В последнее время часто сравнивают CSS и JavaScript, споря о применении этих технологий для решения определённых задач. Споры становятся жарче по мере появления новых замечательных возможностей CSS, которые позволяют упростить решение множества задач и отказаться при этом от JS.



CSS и JavaScript отлично работают в связке, у каждой из этих технологий есть собственные сильные стороны, но я уверен в том, что чем больше CSS используется для контроля внешнего вида и поведения интерфейсов, тем отказоустойчивее и надёжнее будут веб-приложения. Дело тут в следующем:

  • CSS, по своей природе, является технологией, устойчивой к отказам. Это значит, что когда CSS-парсер встречает свойство, которое он не понимает, он просто игнорирует его и идёт дальше. Другими словами, используя CSS, программист применяет стили и ожидает, что они окажутся работоспособными.
  • JavaScript отказоустойчивой технологией не является. Единственная синтаксическая ошибка в JS-коде может нарушить работу целого приложения. То есть, управляя стилизацией сайтов с помощью JS, совершенно необходимо проверять работоспособность соответствующих конструкций.

При ответе на вопрос о том, когда CSS лучше использовать вместо JS, можно рассмотреть и многие другие соображения.

CSS даёт нам новые способы разработки фантастических решений, которые оказываются гораздо проще, чем соответствующие JS-решения, и которые легче создавать. Здесь имеются в виду многие возможности CSS: переходы, пользовательские свойства, анимации, фильтры, математические операции.

В этом материале я расскажу о некоторых интереснейших возможностях CSS (некоторые из них очень свежие), о которых вы, возможно, ещё не знаете. А именно, речь пойдёт о плавном скроллинге, о свойстве position: sticky, и о других возможностях, для реализации которых раньше требовалось написать немало строк хитроумного JS-кода.

1. Плавная прокрутка


Раньше, для оснащения страницы плавной прокруткой, требовалось задействовать несколько строк JS-кода. А теперь эта задача может быть решена исключительно средствами CSS. Ну не замечательно ли это? Теперь воспользоваться плавной прокруткой можно, прибегнув к CSS-свойству scroll-behavior.

Вот как это выглядит:

html {scroll-behavior: smooth;}


Реализация плавной прокрутки

Вот пример на CodePen

Во время написания этого материала свойство scroll-behavior поддерживается лишь в Chrome и Firefox. Его пока не поддерживают Edge, IE и Safari (настольная и мобильная версии). Подробности о поддержке этого свойства можно узнать на Can I Use.

2. Закрепление элементов


Закрепление элементов это одна из моих любимых возможностей CSS. Речь идёт о том, что соответствующие элементы не исчезают из области просмотра при прокрутке страниц. Теперь для закрепления элементов на страницах нет нужды прибегать к offsetTo и window.scrollY в JS. В наши дни можно просто воспользоваться CSS-свойством position: sticky:

header {position: sticky;top: 0;}


Навигационный блок упирается в верхнюю границу области просмотра и не исчезает при прокрутке страницы

Вот проект на CodePen, в котором приведён пример использования свойства position: sticky

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

Взглянем на следующий HTML-код:

<main class="container"><nav class="nav"><ul><li>Home</li><li>About</li><li>Contact</li></ul></nav><div class="main-content">Main Content</div><footer class="footer">Footer</footer></main>

Меню (элемент nav из этого примера) можно будет зафиксировать только в области, которую перекрывает его родительский элемент (main в нашем примере). В результате при использовании свойства position: sticky можно выделить два основных класса элементов:

  • Закрепляемый элемент: это тот элемент, к которому мы применяем свойство position: sticky (nav в нашем случае). Этот элемент будет перемещаться в пределах родительского элемента до тех пор, пока не дойдёт до заданной позиции. Например это может быть top: 0px.
  • Контейнер закрепляемого элемента: это HTML-элемент, в котором содержится закрепляемый элемент. Это та область, в пределах которой может перемещаться закрепляемый элемент. Этот контейнер определяет границы, в которых может существовать закрепляемый элемент.

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

Данная возможность отличается практически 100% браузерной поддержкой.

3. Обрезка текста


CSS даёт в наше распоряжение два чудесных свойства: text-overflow и line-clamp. Они позволяют обрезать тексты, аккуратно обращаясь со словами, и при этом избавляют нас от необходимости использовать для решения подобных задач JavaScript или какие-то другие сложные методы. Оба свойства не новы, но крайне полезны.


Обрезка текстов

Вот пример на CodePen

Давайте подробнее поговорим о свойствах text-overflow и line-clamp.

Свойство text-overflow


Это свойство управляет тем, как текст выводится в ситуациях, когда он, если не помещается в одной строке, должен быть обрезан. Пример такой ситуации показан на вышеприведённом рисунке, в заголовке карточки. Тут можно воспользоваться конструкцией text-overflow: ellipsis, что приведёт к тому, что в конец обрезаемого текста будет добавлен Unicode-символ ().

Для того чтобы свойство text-overflow: ellipsis сделало бы своё дело, необходимо использовать так же свойства white-space: nowrap и overflow: hidden.

.card-title {overflow: hidden;white-space: nowrap;text-overflow: ellipsis;}

Эта возможность отличается практически полной поддержкой во всех современных браузерах.

Свойство line-clamp


Это свойство приходит нам на помощь в тех случаях, когда надо работать не с однострочным, а с многострочным текстом (пример такого текста это содержимое карточки с вышеприведённого рисунка). Хотя это часть стандарта CSS Overflow Module Level 3, который сейчас имеет статус рабочего черновика (Working Draft), данное свойство уже поддерживают порядка 95% браузеров, правда, с префиксом -webkit-. Перед его использованием важно учитывать то, что оно не даёт возможности управления количеством выводимых символов. Но оно, в любом случае, невероятно полезно.

Нам, чтобы им пользоваться, надо прибегнуть к старой реализации flexbox, применив свойства display: -webkit-box и -webkit-box-orient: vertical. Вот как это выглядит:

.card-description {overflow: hidden;display: -webkit-box;-webkit-box-orient: vertical;-webkit-line-clamp: 3;}

4. Пользовательские CSS-свойства: CSS-переменные


В JavaScript-мире препроцессоры CSS (вроде Sass, Less и Stylus) это очень полезные и популярные технологии. Препроцессоры расширяют возможности CSS, позволяя пользоваться, например, переменными и функциями. Но современным веб-дизайнерам доступны мощные стандартные возможности CSS, известные как пользовательские CSS-свойства или CSS-переменные.

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

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

Создавать CSS-переменные очень просто. А именно, для объявления переменной достаточно поставить два тире (--) перед её именем. После этого, там, где нужно значение переменной, вызывают функцию var(), передавая ей созданную ранее переменную в качестве аргумента. Как видите, всё очень просто.

:root {--base: #ffc600;--spacing: 10px;--blur: 10px;}img {padding: var(--spacing);background: var(--base);-webkit-filter: blur(var(--blur));filter: blur(var(--blur));}.hl {color: var(--base);}

CSS-переменными можно управлять из JavaScript.


Использование CSS-переменных

Вот пример на CodePen, где показано использование CSS-переменных и управление ими из JS-кода

5. Обеспечение поддержки тёмной темы


С тех пор, как компания Apple представила в прошлом году тёмную тему для macOS, и благодаря тому, что CSS дал нам возможность обнаруживать применение этой темы с использованием медиазапроса, многие крупные веб-проекты (например, вроде Twitter и Google Maps) такой темой обзавелись (вот список проектов, которые поддерживают тёмную тему).

Тёмная тема это не просто способ украшения веб-страниц. Она способна реально помочь некоторым людям работать в интернете.

Вот несколько цитат.

А ещё есть люди, которые, по объективным причинам, нуждаются в тёмном режиме. Они используют этот режим как одно из средств, предназначенных для людей с ограниченными возможностями. Например, речь идёт о людях со слабым зрением.

Томас Штайнер, Customer Solutions Engineer, Google, Германия.

У Молли синдром Ушера. Из-за этого она ничего не слышит, а поле зрения одного из её глаз ограничено 5 градусами. () Просмотр страниц в тёмном режиме будет ей по силам. Этот режим может пригодиться и другим людям, расширяя возможности по работе в интернете для тех, у кого болит голова, или для тех, кому приходится сидеть за компьютером в плохо освещённой комнате. Если при разработке чего-либо ориентироваться лишь на некоторых особенных пользователей, это окажется полезным далеко не только им.

Чарльз Рейнольдс, дизайнер, правительство Великобритании.

Кроме того, из материала Томаса Штайнера можно узнать о том, что использование тёмной темы способствует экономии энергии: () как известно, использование тёмного режима на AMOLED-дисплеях позволяет сэкономить немало энергии. Исследования в сфере Android-устройств, направленные на популярные приложения Google, вроде YouTube, показали, что в некоторых случаях экономия энергии может достигать 60%.

Новая возможность CSS, которая позволяет нам узнавать о том, включена ли у пользователя тёмная тема, представлена медиа-функцией prefers-color-scheme. Она уже совместима с Chrome, Firefox, Safari и Opera.

Если скомбинировать эту возможность с CSS-переменными, это значит, что веб-разработчику будет очень легко сделать так, чтобы его посетители могли бы с удобством пользоваться возможностями динамической настройки светлого и тёмного режимов.

:root {--color: #222;--background: #eee;--text: 'default';}body {color: var(--color);background: var(--background);}body:after {content: var(--text);display: block;text-align: center;font-size: 3rem;}@media (prefers-color-scheme: light) {:root {--color: #222;--background: #eee;--text: 'light';}}@media (prefers-color-scheme: dark) {:root {--color: #eee;--background: #222;--text: 'dark';}}


Автоматическое обнаружение темы, используемой устройством

В данном CodePen-проекте оформление страницы зависит от того, какую тему использует тот, кто просматривает этот пример

6. Директива supports


Долгое время веб-разработчикам приходилось прибегать к сторонним решениям (вроде JS-инструмента Modernizr) для выяснения того, поддерживаются ли некие возможности CSS текущим браузером. Например, настраивая свойство элемента -webkit-line-clamp, можно проверить, поддерживается ли это свойство в браузере, и, если это не так, можно воспользоваться каким-то запасным вариантом.

После того, как в CSS появилась директива @supports, проверять возможности браузеров стало можно прямо из CSS-кода.

Директива @supports очень похожа на медиазапросы. Она поддерживает различные комбинации выражений, построенные с помощью условных операторов AND, OR и NOT:

@supports (-webkit-line-clamp: 2) {.el {...}}

Здесь проверяется, поддерживает ли браузер свойство -webkit-line-clamp. Если это так, то есть, если условие оказывается истинным, будет применён стиль, объявленный внутри директивы @supports.

Эту возможность поддерживают все современные браузеры.

Итоги


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

Современный мир фронтенда быстро меняется, в нашем распоряжении постоянно появляются новые возможности, помогающие нам быстрее и качественнее делать наше дело. Эксперименты с CSS и изучение нового это не только очень полезно, но и крайне интересно. Советую вам попробовать то новое, о чём вы сегодня узнали.

А вам известны какие-нибудь свежие возможности CSS, которые позволяют решать те же задачи, которые раньше решали только с использованием JavaScript?

Подробнее..

Нативный способ покрасить SVG-иконки

22.07.2020 18:16:54 | Автор: admin
Когда вам нужна возможность менять цвет иконок через CSS, что вы делаете? Вариантов не так много.

Обычно используются либо шрифты иконок, либо исходный код SVG скачивается и вставляется в HTML вручную. Шрифт нужно оптимизировать, иначе пользователь загрузит разом все иконки без надобности. Работа с исходным кодом требует тяжелых DOM-операций и потенциально опасна.

Чтобы защититься от вредоносного кода SVG нужно почистить. Встроенный в Angular санитайзер, к примеру, не работает с SVG и превращает их в пустую строку. Можно воспользоваться проверенным инструментом DOMPurify и подключить его с помощью нашей библиотеки ng-dompurify, о чем я подробно рассказывал.

Давайте посмотрим на еще один способ, доступный в современных браузерах, тэг USE.



Чем нам полезен USE?


Этот тэг задуман для переиспользования символов и целых SVG-блоков на странице. Но в современных браузерах (прости, IE) он может даже доставать внешние ресурсы!

Внешние SVG должны быть на том же домене, так что CDN не подойдет. Пока.

Это позволяет нативным образом вставить SVG в Shadow DOM, почти как тэг IMG с атрибутом src, только с возможностью использовать CSS. И оно даже само работает с кэшем! Но нужно слегка подготовить иконки. Вот что надо сделать:



Сначала в каждой иконке нужно сделать символ с уникальным id и переместить viewBox в него.

Затем надо назначить fill (или stroke) на currentColor, чтобы потом использовать CSS-правило color для задания цвета. Можно также задать эти атрибуты в inherit на других элементах, что позволит сделать двухцветные иконки (подробнее в примере ниже).

Когда наши иконки подготовлены, остается только скинуть их в папку assets и использовать:



Компонент именованных иконок для Angular


Писать путь и обращаться к символу каждый раз утомительно. Давайте сделаем Angular-компонент, который будет находить иконки по имени. С помощью Dependency Injection это сделать очень просто.

Нам понадобится токен для предоставления пути до всех наших иконок и простой компонент. Он будет формировать href исходя из имени и заданного пути. Мы даже можем повесить его на нативный SVG с помощью селектора: так мы вынесем наружу заботу о размере.

Надо иметь в виду, что Safari до 12.1 поддерживает только устаревший синтаксис xlink:href. Так что лучше использовать оба варианта.

Сделаем stroke и fill прозрачными для использования нескольких цветов в CSS:



Живой пример: stackblitz.com/edit/angular-colored-svg

Заключение


У этого подхода есть ограничения отсутствие поддержки IE и кросс-доменности. Однако, если они для вас не критичны, данное решение может стать хорошей альтернативой другим способам.

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

Правосторонний интерфейс адаптируем контролы к right-to-left языкам

23.07.2020 14:23:59 | Автор: admin
C адаптацией приложений и сайтов под RTL-языки (right-to-left, справа налево) сталкиваются разработчики многих развивающихся и выходящих на новые рынки продуктов. Мы в Badoo тоже в какой-то момент оказались в этой ситуации: наши приложения переведены на 52 языка и диалекта. В этой статье я расскажу о нескольких интересных нюансах, которые мы обнаружили при адаптации форм на сайте Badoo.сом под иврит и арабский язык.




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

Если нет, то вот несколько полезных ссылок для понимания проблем и решений:


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

У этой проблемы есть две составляющие ввод контента и вывод его и обе по-своему интересны. При этом вторая широко освещена в указанных выше и других статьях, а вот первая нет. Для её решения есть несколько хитростей, показавшихся нам достойными того, чтобы поделиться ими с читателями Хабра.

Для начала сравним несколько RTL-интерфейсов приложений, для которых RTL-аудитория не пустяк, и посмотрим, как они справляются с задачей ввода текста.

Пример 1. Одна социальная сеть


1.1 Форма авторизации


В форме логина на главной странице поле E-mail по умолчанию ведёт себя как LTR. Это довольно разумно, так как большинство электронных адресов содержит только латиницу.





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

  • выровнен по левой стороне;
  • в процессе написания символов @ и ., имеющих нейтральную типизацию, вся конструкция будет менять свое положение, что не очень удобно.



Поле для ввода пароля по умолчанию RTL, курсор находится справа.



Но что будет, если мы попробуем ввести пароль из латинских символов или цифр? По мере ввода курсор будет располагаться слева от вводимого текста. Это не критично, поскольку пароль мы всё равно не видим (до тех пор, пока у нас нет кнопочки Показать пароль), но поведение поля можно было бы улучшить, показав юзеру, в какой раскладке он вводит пароль. Специфика RTL-интерфейсов в том, что, несмотря на то, что большая часть текста правосторонняя, пользователям приходится очень часто переключать раскладку клавиатуры для ввода e-mail, логина, пароля, которые обычно пишутся LTR. Небольшая подсказка здесь была бы кстати.



1.2 Форма регистрации


Теперь посмотрим на форму регистрации, также расположенную на главной странице.



Тут видно, что все поля однозначно считаются RTL и выровнены по правому краю, что не очень удобно, когда имеешь дело с LTR-текстом. Особенно неприятно становится при вводе e-mail символы @ и . заставляют части адреса меняться местами в процессе набора. То, что было не очень критично для редких RTL-адресов в предыдущем примере, становится критичным для LTR.



1.3 Мессенджер компактный


Мессенджер один из ключевых инструментов этого приложения. Тут-то уж точно всё должно быть идеально. Взглянем на компактную версию:



И правда. Поле считается RTL по умолчанию, но, как только мы начинаем вводить LTR-текст, его направление меняется на удобное для ввода. Ничего не прыгает. Давайте удостоверимся, что в развёрнутой версии тоже всё в порядке.

1.4 Мессенджер развёрнутый


Упс! Несмотря на то, что латинский текст в RTL-поле ведёт себя правильно, он выровнен по правому краю. Некритично, но непонятна логика: почему поведение идеологически одного и того же компонента различается?



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

Можно ли здесь что-то улучшить? Мы считаем, что да. Причём весьма простыми способами, о них ниже.

Пример 2. Довольно известная почтовая служба


2.1 Форма авторизации


Здесь разработчики исходят из принципа обязательного выравнивания по правому краю, но сохраняют отношение к вводимому контенту как к LTR. Это приводит к нескольким неудобным моментам, схожим с показанными в предыдущих примерах.

Например, поле для ввода e-mail ожидает вводимый текст справа.



Впрочем, вводимый LTR-текст ведёт себя как положено, без каких-либо прыжков (а использование нелатинских символов в этом почтовом сервисе запрещено).

Забегая вперёд, скажем, что в современном вебе носителям RTL-языков в первую очередь важно, чтобы текст вёл себя в соответствии с его содержимым и направлением в документах. По поводу выравнивания текста в поле нет однозначного мнения, и пользователи уже привыкли к обоим вариантам: для кого-то более привычно выравнивание по левому краю, для кого-то по правому, но, в целом, большого значения это не имеет. Мы в Badoo, проконсультировавшись с переводчиками, решили придерживаться логичного расположения текста и не выравнивать его принудительно.



Более интересное поведение у поля для ввода пароля. Оно тоже принудительно выровнено по правому краю и тоже считается LTR, что, на наш взгляд, ведёт к потере полезной информации о раскладке клавиатуры в случае ввода текста на RTL-языке.



А при включении отображения пароля всё становится совсем плохо, так как нейтральные символы заставляют пароль прыгать, как это происходит в случае e-mail в предыдущих примерах. Так, в примере со следующего скриншота восклицательный знак должен идти первым, а курсор должен быть слева.



2.2 Форма регистрации

Форма регистрации внезапно гораздо более дружелюбна к пользователям. Но это логично вводимая в неё информация более разнообразна. Тут как минимум появляются имя и фамилия.

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



Единственное исключение поле адреса. Тут выравнивание по левому краю. Немного странно выглядит.



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



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

Опыт Badoo


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

  • плейсхолдеры должны быть выровнены в зависимости от направления языка интерфейса;
  • вводимый текст должен автоматически занимать левую или правую сторону поля в зависимости от своего направления;
  • курсор в пустом поле должен быть выровнен в зависимости от направления языка интерфейса;
  • вводимый текст в полях для ввода телефона, URL всегда должен занимать левую сторону;
  • поля для ввода e-mail ожидают левосторонний текст, но готовы и к правостороннему;
  • курсоры в пустых полях для ввода e-mail, телефона, URL выровнены по левой стороне.

И попробуем добиться этого.

Для начала рассмотрим поле для обычного текста, например имени без каких-либо трюков.

<html lang=he dir=rtl>...<input type="text">...</html>



Курсор располагается справа как положено, потому что тег INPUT наследует направление текста от HTML и для правостороннего интерфейса мы ожидаем, что введённый текст, скорее всего, будет правосторонним.

Но что будет, если мы начнём вводить LTR-символы? Уже знакомая нам ситуация с непривычным курсором слева.



В примерах выше разработчики подходят к решению проблемы сурово: следят за вводимыми символами с помощью JavaScript и меняют атрибут dir на лету. Это имело смысл до недавнего времени, но сейчас все современные браузеры отлично понимают атрибут dir=auto и сами справляются с разворачиванием текста. Давайте добавим его.

<input type="text" dir=auto>

Получилось то что надо.



Попробуем добавить к полю плейсхолдер.

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

<input type="text" dir=auto placeholder= >

Ой! Почему-то всё выровнялось по левому краю, включая плейсхолдер.



Дело в атрибуте dir=auto. При отсутствии контента браузер может считать направление текста левосторонним. Попробуем разместить плейсхолдеры по правому краю. Обычно это текст на языке интерфейса, так что автоматическое расположение нам не очень нужно.

input::placeholder {    direction: rtl;}



Стало гораздо лучше. Только вот положение курсора смущает он по-прежнему слева. Попробуем стилизовать пустой INPUT с помощью прекрасного псевдокласса :placeholder-shown.

input:placeholder-shown {    direction: rtl;}

К сожалению, в инпутах без плейсхолдера свойство :placeholder-shown не будет работать. Исправить это можно, добавив ко всем таким полям пустой плейсхолдер:

<input type="text" dir=auto placeholder= >

Вот теперь всё как надо. Плейсхолдер справа, курсор справа (потому что в первую очередь ожидаем RTL-текст), текст справа или слева в зависимости от того, на каком языке печатаем.



Но этого недостаточно.

Мы помним, что электронные адреса могут содержать в себе любые символы. Поэтому код такого INPUT будет похож на предыдущий.

<input type="email" dir=auto placeholder=    >

(На Badoo мы ожидаем в первую очередь ввода e-mail, но также допускаем ввод номера телефона, поэтому в плейсхолдере написано об этом.)

Но хотя символы могут быть любые, в первую очередь мы ожидаем ввода адреса латиницей (и в нашем случае номера телефона цифрами). То есть курсор в пустом поле должен быть слева. Сделаем исключение в CSS.

input[type='email']:placeholder-shown {    direction: ltr;}

На этом не стоит останавливаться. У нас ещё остались поля с типами tel, number, url. Они всегда левосторонние, поэтому для них пишем такой код:

<input type="tel" dir=ltr placeholder= >

И добавляем исключения для пустых полей:

input[type='tel']:placeholder-shown,input[type='number']:placeholder-shown,input[type='url']:placeholder-shown {    direction: ltr;}

Вот теперь стало так, как мы планировали.



Совсем маленький штрих для тех, кому небезразлична судьба IE11. Этот браузер не понимает атрибут dir=auto, поэтому автоматической смены направления текста не добиться без привлечения JavaScript.

Но мы всё равно даём возможность пользователям удобно вводить электронные адреса и номера телефонов.

.ie11 input[type="email"],.ie11 input[type="tel"] {    direction: ltr;}.ie11 input[type="email"]:-ms-input-placeholder,.ie11 input[type="tel"]:-ms-input-placeholder {    direction: rtl;}

Если собрать весь CSS, добавить префиксы и препроцессор SCSS, то получится что-то такое (да-да, мы помним, что поля INPUT могут, например, иметь тип checkbox, но для простоты проигнорируем этот момент):

[dir=rtl] input {   &::-webkit-input-placeholder {       direction: rtl;   }   &::-moz-placeholder {       direction: rtl;   }   &:-ms-input-placeholder {       direction: rtl;   }   &::placeholder {       direction: rtl;   }   &:placeholder-shown[type='email'],   &:placeholder-shown[type='tel'],   &:placeholder-shown[type='number'],   &:placeholder-shown[type='url'] {       direction: ltr;   }}.ie11 [dir=rtl] input {   &[type="email"],   &[type="tel"] {       direction: ltr;       &:-ms-input-placeholder {           direction: rtl;       }   }}

Мы в Badoo делим стили на LTR и RTL, поэтому у нас каскада от [dir=rtl] нет, и свойства для LTR мы пишем так, чтобы они перевернулись в RTL. Но принцип, думаю, понятен.

Для TEXTAREA схема такая же за одним исключением: там не нужно учитывать типы полей и размещать курсор или текст у левого края контент всегда автоматически разворачивается за счёт атрибута dir=auto.

Важный момент, о котором нельзя забывать: все требования к полям применимы и к LTR-интерфейсам. Вводимое имя на иврите или арабском должно показываться справа, курсор в нём должен быть слева. Редкий любитель экзотического электронного адреса с правосторонними символами должен видеть свой e-mail так, как он его вводит справа налево.

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

Как стать Front-End разработчиком

25.07.2020 02:14:21 | Автор: admin
image

Кто такой Front-End разработчик?


Front-End разработчик это человек который пишет код для внешнего вида сайта, также есть Back-End разработчик который пишет код для функциональной части сайта. Если скрестить эти две профессии получится Full-Stack разработчик

1. Азы которые нужно знать


Для написания Front-End кода можно использовать множество языков, но для начала я советую вам начать изучения с языка HTML. С помощью его вы сможете делать конечно не сайты, но стандартные интернет страницы с текстом, картинками и т.д, но HTML-я вам конечно же не хватит что бы считать себя Front-End разработчиком. Способов изучить HTML есть много их мы разберём немного позже

image

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

Что бы хорошо писать дизайн для сайта вам не всегда хватит языка CSS, поэтому вам нужны азы JavaScript-а. Но если-же вы полностью выучите язык JavaScript и Node.js вы вполне сможете писать даже Back-End и стать Full-Stack разработчиком

image

2. Время


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

image

3. Математика


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

4. Обучающие ресурсы


Для азов HTML и CSS посоветую эти видео
HTML: www.youtube.com/watch?v=5pBcKKiZSGE
CSS: www.youtube.com/watch?v=iPV5GKeHyV4
После можете читать и узнавать аспекты HTML и CSS на htmlbook.ru

Для азов JavaScript советую это видео
www.youtube.com/watch?v=Bluxbh9CaQ0&t=5328s
Потом JavaScript во всех аспектах можно доучить на learn.javascript.ru
Подробнее..

Дайджест свежих материалов из мира фронтенда за последнюю неделю 425 (20 26 июля 2020)

27.07.2020 00:14:29 | Автор: admin
Предлагаем вашему вниманию подборку с ссылками на новые материалы из области фронтенда и около него.


Медиа|Веб-разработка|CSS|JavaScript



Медиа


podcast Подкаст Фронтенд Юность (18+) 147: Jenkins забирает код у Медиазоны
podcast Подкаст CSSSR: Chrome 84, Safari 14 Beta, Ember Roadmap 2020, Yandex UI Kit, Open Prioritization, Oracle Update
podcast Подкаст Сделайте мне красиво, Выпуск 38: Кортежи в js, преоптимизация useCallbacks и яма с SPA

Веб-разработка


habr Пришло время ленивой загрузки закадровых <iframe>
habr Правосторонний интерфейс: адаптируем контролы к right-to-left языкам
Yaml для веб разработчиков
Авторизация и аутентификация для всех
Google отложил переход на mobile-first индексацию до марта 2021 года
en Полноценный HTML в GitHub README с помощью SVG foreignObject
en Введение в Jamstack: создание безопасных, высокопроизводительных сайтов
en Используйте Chrome DevTools как Senior Frontend Developer
en 5 стратегий Service Worker кэширования для вашего следующего PWA приложения



CSS


habr Современные решения старых CSS-задач: Удержание футера внизу страницы, Элементы одинаковой высоты: Flexbox vs Grid, Масштабирование изображений на CSS
habr Нативный способ покрасить SVG-иконки
habr О конфликтах Sass и сравнительно новых возможностей CSS
Объяснение ключевых слов initial, inherit, unset иrevert вCSS
en @property: наделяем суперспособностями CSS переменные
en Современные методы CSS для улучшения читабельности
en keyframes.app визуальный онлайн инструмент, облегчающий создание CSS для анимаций
en Использование Flexbox с text ellipsis
en Анимированное подчеркивание на CSS
en О том, как использовать множественные фоны в CSS
en Когда вы используетеinline-block?
en Онлайн-генератор изображений трехмерных книг на CSS
en css-media-vars Новый способ написания адаптивного CSS. Именованные точки останова, DRY селекторы, без скриптов, без сборок, ванильный CSS.
en За пределами размеров экрана: отзывчивый дизайн в 2020 году
en Реалистичные капли на CSS

JavaScript


habr Выбор зависимостей JavaScript
habr Путь к пониманию шаблонных литералов в JavaScript
en Реактивный jQuery для спагетти-кода
en Импорт не-ESM-библиотек в ES-модули с ванильным JS








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



Дайджест за прошлую неделю.
Материал подготовили dersmoll и alekskorovin.
Подробнее..

Визуальное сравнение 13 CSS-фреймворков

27.07.2020 10:17:57 | Автор: admin


Доброго времени суток, друзья!

Предлагаю Вашему вниманию результаты небольшого исследования визуального сравнения 13 CSS-фреймворков.

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

В исследовании представлены следующие фреймворки:


Использовались следующие версии стилей:



В тестовой разметке представлены основные элементы веб-страницы с акцентом на семантические теги:

<header>    <figure>        <figcaption>logo</figcaption>        <img src="logo.png" alt="logo">    </figure>    <nav>        <a href="#">link1</a>        <a href="#">link2</a>        <a href="#">link3</a>    </nav></header><hr><main>    <h1>main title</h1>    <aside>        <h4>aside title</h4>        <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Praesentium, quibusdam.</p>    </aside>    <section>        <h2>section title</h2>        <p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Odit, illum.</p>        <ul>            <li>item1</li>            <li>item2</li>            <li>item3</li>        </ul>        <table>            <caption>table</caption>            <tr>                <th>1</th>                <th>2</th>                <th>3</th>            </tr>            <tr>                <td>1</td>                <td>2</td>                <td>3</td>            </tr>            <tr>                <td>4</td>                <td>5</td>                <td>6</td>            </tr>        </table>        <dl>            <dt>term</dt>            <dd>Lorem <strong>ipsum</strong>, dolor sit <em>amet</em> consectetur adipisicing elit. <mark>Accusamus</mark>, obcaecati?</dd>        </dl>        <details open>            <summary>summary</summary>            <p><small>Lorem dolor sit amet ipsum, consectetur adipisicing elit. Explicabo, repellat?</small></p>        </details>        <button>button</button>    </section>    <article>        <h3>article title</h3>        <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Nam, architecto?</p>        <blockquote>Lorem ipsum dolor, sit amet <cite>consectetur adipisicing elit.</cite> Ipsam, ad!</blockquote>        <code>            console.log('hello world')        </code>    </article></main><hr><footer>    <form action="#">        <fieldset>            <legend>form</legend>            <label>name:                <input type="text">            </label>            <label>email:                <input type="email">            </label>            <input type="submit" value="subscribe">        </fieldset>    </form>    <p> 2020.</p></footer>

Вот как это выглядит:




Поиграть с кодом можно здесь:



Песочница не позволяет работать с тегом head, поэтому милости прошу на GitHub Pages.

Код проекта находится здесь.

Результаты исследования вполне ожидаемы: первое место Bootstrap, второе Materialize.

Materialize, судя по всему, следует концепции mobile first, из-за чего проигрывает Bootstrap, когда дело касается широких экранов. Также Materialize проигрывает в плане функциональности, но это другая история.

Перспективными мне показались Skeleton и Picnic.

Благодарю за внимание.
Подробнее..

1С справа налево как мы поддержали RTL в платформе 1С Предприятие

30.07.2020 12:15:48 | Автор: admin
Платформа 1С:Предприятие локализована на 22 языка, включая английский, немецкий, французский, китайский, вьетнамский. Недавно, в версии 8.3.17, мы поддержали арабский язык.
Одна из особенностей арабского языка в том, что текст на нём пишут и читают справа налево. UI для арабского языка надо отображать зеркально по горизонтали (но не всё и не всегда тут есть тонкости), контекстное меню открывать слева от курсора и т.п.
Под катом о том, как мы поддержали RTL (right-to-left) в веб-клиенте платформы 1С:Предприятие, а ещё одна из гипотез, объясняющая, почему арабский мир пишет справа налево.
image

Немного истории


Для нас привычно письмо слева направо. Это направление письма во многом порождено тем фактом, что при записи текста на бумаге правши (а их, по статистике, около 85%) видят то, что уже написано пишущая (правая) рука не закрывает написанный текст. Левшам же приходится мучиться.

Одна из гипотез почему в арабском языке используется письмо справа налево звучит так. Языки, от которых берет свое начало арабский, зародились в те времена, когда не было бумаги и ее аналогов (папируса, пергамента и т.п.). Был только один способ фиксации информации высекать письмена на камне. А как правшам будет удобнее орудовать молотком и зубилом? Конечно же, держа зубило в левой руке и стуча по нему молотком, зажатым в правой. А в этом случае удобнее писать как раз справа налево.

Ну а теперь о том, как мы разбирались с этим наследием веков :)

Как мы приступали к задаче?


Никто из разработчиков платформы не говорил по-арабски и не имел опыта разработки RTL-интерфейсов. Мы перелопатили массу статей на тему RTL (особенно хочется поблагодарить компанию 2ГИС за проделанную работу и тщательно проработанные статьи: статья 1, статья 2). По мере изучения материала пришло понимание, что без носителя языка нам никак не обойтись. Поэтому одновременно с поиском переводчиков на арабский язык мы стали искать себе сотрудника носителя арабского языка, который бы имел нужный нам опыт, мог бы проконсультировать нас по арабской специфике интерфейсов. Просмотрев несколько кандидатов, мы нашли такого человека и приступили к работе.

Поиграем шрифтами


По умолчанию мы используем в платформе шрифт Arial, 10pt. Разработчик конкретной конфигурации может поменять шрифт у большинства элементов интерфейса, но, как показывает практика, делается этот нечасто. Т.е. в большинстве случаев пользователи программ 1С видят на экранах надписи, написанные Arial-ом.
Arial хорошо отображает 21 язык (включая китайский и вьетнамский). Но, как выяснилось благодаря нашему арабскому коллеге, арабский текст, выведенный этим шрифтом, очень мелкий и плохо читается:

100%:
image

Арабские пользователи, как правило, работают в увеличенном DPI 125%, 150%. В этом DPI ситуация улучшается, но Arial по-прежнему остаётся плохо читаемым в силу особенностей шрифта.

125%:
image

150%:
image

Мы рассмотрели несколько вариантов решения этой проблемы:

  1. Поменять шрифт по умолчанию Arial на другой, одинаково хорошо отображающий все языки, поддерживаемые платформой (включая арабский).
  2. Увеличить размер шрифта Arial до 11pt в RTL-интерфейсе.
  3. Заменить шрифт по умолчанию с Arial на более подходящий для арабского текста, а в LTR-интерфейсе продолжать использовать Arial.

При выборе решения приходилось учитывать, что шрифт Arial размером 10pt используется в платформе 1С:Предприятие очень давно, на платформе создано нами и нашими партнёрами более 1300 тиражных решений, и во всех них шрифт Arial 10pt хорошо себя показал на всех поддерживаемых ОС (Windows, Linux и macOS различных версий), а также в браузерах. Смена шрифта и/или его размера означала бы необходимость массированного тестирования пользовательского интерфейса, и многое в этих тестах автоматизации не поддаётся. Смена шрифта также означала бы, что для текущих пользователей меняется привычный интерфейс программ.

Более того, найти универсальный шрифт, хорошо отображающий все языки, включая арабский, нам не удалось. Например, шрифт Segoe UI хорошо отображает арабский даже при 10pt, но не поддерживает китайский язык, а также не поддерживается в ряде ОС. Tahoma неплохо отображает арабский текст при 10pt, но имеет проблемы с поддержкой в Linux и слишком жирное начертание латиницы/кириллицы в случае жирного шрифта (арабский жирный текст выглядит хорошо). И т.д., и т.п.

Увеличение размера шрифта по умолчанию до 11pt в RTL-интерфейсе означало бы серьёзный объём тестирования пользовательского интерфейса мы должны убедиться, что всё отрисовывается корректно, все надписи помещаются в отведённое для них место и т.п. И даже при размере 11pt Arial показывает арабские символы не идеально.
В итоге оптимальным с точки зрения трудозатрат и достигаемого эффекта оказался третий путь: мы продолжаем использовать Arial для всех символов, кроме арабских. А для арабских символов используем хорошо подходящий для этого шрифт Almarai. Для этого в CSS добавляем:

@font-face {  font-family: 'Almarai';  font-style: normal;  font-weight: 400;  font-display: swap;  src: local('Almarai'),        local('Almarai-Regular'),       url(http://personeltest.ru/aways/fonts.gstatic.com/s/almarai/v2/tsstApxBaigK_hnnQ1iFo0C3.woff2)             format('woff2');  unicode-range:        U+0600-06FF, U+200C-200E, U+2010-2011, U+204F, U+2E41, U+FB50-FDFF, U+FE80-FEFC;}

и далее везде, где нужно использовать шрифт по умолчанию, задаём шрифт таким образом:
font-family: 'Almarai', Arial, sans-serif;

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

Переворот интерфейса


Как и следовало ожидать, HTML-вёрстка веб-клиента не была готова к перевороту. Совершив первый шаг, поставив на корневом элементе атрибут dir=rtl и добавив стиль html[dir=rtl] {text-align: right;}, мы приступили к кропотливой работе. В ходе этой работы мы выработали ряд практик, которыми хотим здесь поделиться.

Симметрия


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

В колонке до RTL графически представлены исходные отступы элементов кнопки. Очевидна зависимость величины отступов от наличия элементов в кнопке, а также от последовательности их расположения. Если есть картинка, то тексту не нужен левый отступ, если картинка справа, то у картинки отрицательный сдвиг, если есть маркер выпадающего списка контейнеру с текстом больше отступ справа, если маркер сразу после картинки у него еще отступ справа. Слишком много если, за исключением кнопки только с текстом, у которого симметричные отступы. Симметричные! Если распределить отступы симметрично, то и переворачивать нечего. Это и стало основной идеей.

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

image

Примечание. Все приведённые ниже примеры по умолчанию приведены для LTR-интерфейса. Чтобы увидеть, как пример выглядит в RTL-интерфейсе, смените dir=ltr на dir=rtl.

<!DOCTYPE html><html dir="ltr"><head><style>.button {    display: inline-flex;    align-items: center;    border: 1px solid #A0A0A0;    border-radius: 3px;    height: 26px;    padding: 0 8px;}.buttonImg {    background: #A0A0A0;    width: 16px;    height: 16px;}.buttonBox {    margin: 0 8px;}.buttonDrop {    display: flex;}.buttonDrop:after {    content: '';    display: block;    border-width: 3px 3px 0;    border-style: solid;    border-left-color: transparent;    border-right-color: transparent;}.buttonImg + .buttonDrop::before {    content: '';    display: block;    width: 8px;    overflow: hidden;}</style></head><body><a class="button">    <span class="buttonImg"></span>    <span class="buttonBox">Настройки</span>    <span class="buttonDrop"></span></a><a class="button">    <span class="buttonImg"></span>    <span class="buttonDrop"></span></a></body></html>

Мы стараемся избегать лишних элементов, псевдоэлементов и обёрток. Но, делая выбор в данном случае между увеличением условий в CSS и добавлением псевдоэлемента, победило решение с псевдоэлементом в силу своей универсальности. Таких кнопок бывает на форме немного, поэтому производительность при добавлении элементов не пострадает даже в Internet Explorer.

Принцип симметрии оказался полезен и при прокрутке наших панелей. Чтобы сдвинуть содержимое по горизонтали, ранее применялось единичное свойство margin-left: -Npx;.

image

Теперь устанавливается значение симметричное margin: 0 -Npx;, т.е. для левого и правого сразу, а куда сдвинуть знает сам браузер, в зависимости от указанного направления.

Атомарные классы


Одной из возможностей нашей платформы является возможность динамически менять контент и его расположение на форме на лету по вкусу каждого пользователя. Нередкий случай изменений выравнивание текста по горизонтали: слева, справа или по центру. Достигается это простым выравниваем text-align с соответствующим значением. Разворот для RTL означал бы расширение условий в скриптах и стилях для каждого контрола и для каждого случая его позиционирования. Минимальное решение обошлось в 4 строчки:

.taStart {    text-align: left;} html[dir=rtl] .taStart {    text-align: right;}.taEnd {    text-align: right;}html[dir=rtl] .taEnd {    text-align: left;}


Таким образом, в необходимых местах происходит установка класса с необходимым выравниванием и его легкая замена в случае необходимости. Осталось только заменить в установку выравнивания с style=text-align: ... на соответствующий класс.
По такому же принципу происходит установка другого вида выравнивания float.

.floatStart {    float: left;} html[dir=rtl] .floatStart {    float: right;}.floatEnd {    float: right;}html[dir=rtl] .floatEnd {    float: left;}


И, как же без него, класс для зеркального отображения, например, иконок, который так же устанавливается в любые контейнеры, где необходим зеркальное отображение в RTL-интерфейсе.

html[dir=rtl] .rtlScale {    transform: scaleX(-1);}


Антискейл


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

Можно перевернуть контейнер с тумблером целиком, но что делать с текстом, который тоже перевернется? Этот прием мы назвали антискейл. Контейнеру, которому необходимо отобразиться зеркально, добавляем атомарный класс rtlScale, а его дочернему элементу добавляем свойство наследования transform: inherit;. В LTR-интерфейсе данный метод будет проигнорирован, а для RTL-интерфейса, текст, перевернувшись дважды, отобразится как надо.

image

<!DOCTYPE html><html dir="ltr"><head><style>html[dir=rtl] .rtlScale {    transform: scaleX(-1);}.tumbler {    display: inline-flex;    border-radius: 4px 0 0 4px;    border: 1px solid #A0A0A0;    padding: 4px 8px;}.tumblerBox {    transform: inherit;}</style></head><body><div class="tumbler rtlScale">    <div class="tumblerBox">не знаю</div></div></body></html>


Flexbox


Конечно же, к сожалению, не мы придумали эту потрясающую технологию, но с большим удовольствием использовали её возможности в наших целях. Например, в панели разделов. Кнопки прокрутки этой панели не занимают места, появляются поверх панели при возможности прокрутки в ту или иную сторону. Вполне логичная реализация position: absolute; right/left: 0; оказалась не универсальной, поэтому мы от неё отказались. В итоге универсальное решение стало выглядеть так: родительскому контейнеру кнопки прокрутки устанавливаем нулевую ширину, чтобы не занимал место, а кнопке прокрутке, расположенной в конце, сменили ориентацию через flex-direction: row-reverse;.

image

Таким образом, кнопка в конце строки прижимается к концу строки контейнера с нулевой шириной и отображается назад поверх панели.

<!DOCTYPE html><html dir="ltr"><head><style>.panel {    display: inline-flex;    background: #fbed9e;    height: 64px;    width: 250px;}.content {    width: 100%;}.scroll {    display: flex;    position: relative;     width: 0; }.scrollBack {    order: -1; }.scrollNext {    flex-direction: row-reverse; }.scroll div {    display: flex;     flex: 0 0 auto;     justify-content: center;     align-items: center;     background: rgba(255,255,255,0.5);     width: 75px; }</style></head><body><div class="panel">    <div class="content">Контент панели</div>    <div class="scroll scrollBack">        <div>Назад</div>    </div>    <div class="scroll scrollNext">        <div>Вперёд</div>    </div></div></body></html>


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

image

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

<!DOCTYPE html><html dir="ltr"><head><style>.anchor {    border: 1px solid red;     position: absolute;     width: 100px;     height: 50px;     max-width: 0;     max-height: 0;     top: 25%;    left: 50%;}.anchorContent {    background: #FFF;     border: 1px solid #A0A0A0;     width: inherit;     height: inherit;     padding: 4px 8px; }</style></head><body><div class="anchor">    <div class="anchorContent">Контент якоря</div></div></body></html>


Абсолютно спозиционированные элементы


Там, где нельзя обойтись без абсолютного позиционирования элементов (style=position: absolute; или style=position: fixed;), dir=rtl бессилен. На помощь приходит подход, когда горизонтальная координата применяется не к стилю left, а right.

image

При этом если в JS при расчётах координат идёт обращение к свойствам scrollLeft, offsetLeft у элементов, то в RTL-интерфейсе использование этих свойств напрямую может привести к неожиданным последствиям. Нужно высчитывать значение этих свойств по-другому. Хорошо зарекомендовала себя реализация подобного функционала в Google Closure Library, которую мы используем в веб-клиенте: см. https://github.com/google/closure-library/blob/master/closure/goog/style/bidi.js.

В итоге


Мы это сделали! Перевернули и сохранили наш исходный код в едином варианте под LTR и RTL-интерфейсы. Необходимости пока не возникло, но при желании мы сможем на одной странице отобразить две формы разной направленности одновременно. И кстати, применив наши приёмы, в итоге мы получили итоговый CSS-файл легче на 25%.
А ещё мы поддержали RTL в тонком (нативном) клиенте 1C, который работает в Windows, Linux и macOS, но это тема для отдельной статьи.
Подробнее..

Хватить это верстать дважды или 2-х сторонняя связь между дизайном и кодом

30.07.2020 14:08:36 | Автор: admin

Как "подружить" дизайнера и инженера? Как дать им работать с одними и теме же данным, без ущерба продуктивности? Как хранить дизайн в системе контроля версий. Если вас интересуют эти вопросы, в такой же степени как и меня, то добро пожаловать под кат!


Данная статья это прямое продолжение "Хватит это верстать, ударим автоматизацией по макетам" и является результатом моих исследований интересующей меня проблемы.


В первой части я, вкратце, описал проблематику как самой вёрстки, так и её автоматизации. Так же поделился своими результатами исследования этой темы. Остановился же я на вопросе контролируемости автоматизируемой вёрстки.


В данной статья я раскрою более подробно это понятие и поделюсь результатами своих исследований.
Хочеться с чем-то поиграться? Вот проверка концепции.


Контролируемость


А о какой контролируемости вообще идёт речь?
Я выделил два основных положения:


  1. Возможность влиять на процесс генерации HTML кода.
  2. Прямое редактированию результата, которое будет учтено при последующей генерации.

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


Но более подробный разбор этой темы останется за рамками данной статьи, сейчас же я сосредоточусь на втором положении.


Проблематика


Многие графические дизайн решения предлагают экспорт HTML кода, но на этом и останавливаются. HTML код является производным продуктом и любые его изменения будут утеряны при новой версии генерации.


Таким образом построение интерфейса и приложений на данном подходе является весьма затруднительным. Не говоря уже о качестве генерируемого кода. Этого вполне достаточно для решаемых задач подобных сервисов, как генераторы лендингов или прототипирования. Но для приложений, максимум на что они пригодны быть быстрым стартом для чего-то более сложного.



Решение


Главная идея если макеты делаются для создания HTML документа, то весь макет можно описать в HTML и CSS.


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



Но если макет описан в HTML документе, то что мешает разработчику открыть код и дописать логику, оживить макет там, где это невозможно сделать с использование визуального редактора? Ответ ничего, да с оговорками, но это возможно.
Таким образом у нас появляется 2х сторонняя связь между инструментом дизайна и исходным кодом.


Возможно, кто-то скажет, что это звучит как утопия, Unity 3D, скажу я в ответ.


Unity, как и любой другой игровой движок уже давно реализовали подобную концепцию в своих инструментах.


Моё мнение, единственное препятствие внедрения подобного подхода в веб индустрии и производных высокие требования к HTML разметке, этот вопрос я более подробно рассмотрел в предыдущей статье.


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



Хорошо, я хочу иметь что-то типо Unreal Engine, но для WEB. С чего вообще начать?
У меня есть на руках:


  1. Простой Drag&Drop визуальный редактор;
  2. Концепт модуля генерации разметки;
  3. Какой-то HTML код, что я хочу редактировать.

Первым вопросом стало, как это всё объединить вместе.


Движёк


Любой движёк состоит из модулей, значит с этого и стоит начать.


Ух, тут прям в голову начинают лезть мысли о модуле мокирования api, тестирования, управлением хранилищем, создания анимации, оптимизации, работы с зависимостями, документирования



Но стоит поумерить пыл и вернуться к текущей проблематике.


Модуль отображения


Возможно вопрос и очевидный, но вообще, что мы и где рисуем?


У нас есть HTML код, который мы должны чем-то прочитать и отобразить. Логичным выбором тут будет самый популярный рендер WebKit Blink, его мы используем как модуль отображения(рендеринга).


Модуль чтения-записи


А вот с модулем чтения всё не так очевидно. Пока речь идёт о единой точки входа (весь код лежит в index.html), никаких проблем нет. Но реальное приложение может иметь сколь угодно сложную архитектуру и храниться в любом формате.
Пока видится 3 варианта как с этим справиться:


  1. Работа с финальным кодом, с промежуточным рендерингом;
  2. Максимальное покрытие всех стеков популярных технологий;
  3. Строгое стандартизирование.

Чистого варианта тут нет, каждый имеет свои минусы.


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


Первый же вариант кажется очень перспективным, но с рядом сложных моментов, решение которых может оказаться дольше, чем 2.


Из очевидных проблем:


  1. Сопоставлени промежуточного с оригинальным;
  2. Приведение промежуточного кода, к формату оригинального.

Проблемы интересные и требуют исследований.


Модуль создания разметки


По всей видимости, самая простая часть.


Модуль визуального взаимодействия


А с чем мы вообще можем взаимодействовать?


Вот так выглядит дерево на одном из лендингов, описывающее 2 блока, лежащие рядом.



Глядя на него, вспоминается Adobe Illustrator в котором, чтобы добраться до нужного элемента, нужно кликнуть на одно и то же место 2 * N раз. Если там это оправдано, то в редакторе интерфейса это совсем неуместно.


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


Этот факт хорошо иллюстрирует следующую концепцию не весь HTML код значим одинаково.


Из этого сформулируем правило. HTML код делится на:


  1. Значимый и;
  2. Незначимый.

Пользователь взаимодействует со значимыми элементами.


Причём значимым может быть как код, описывающий внешний вид, так и структуру дерева группировки, позиционирование и тп.


Сам же редактор должен соответствовать всем ожиданиям дизайнера.


Связь


А что мы вообще имеем и что с чем связываем?
У нас есть:


  1. Код, как источник правды;
  2. DOM дерево;
  3. Визуальное отображение.

При изменении кода, меняется DOM, что приводит к перерисовки отображения.



При изменении визуального отображения мы можем:


  1. Изменить DOM, сохранить производный результат в код.
  2. Изменить код, что приведёт к изменению DOM.


Каждый из вариантов приведет к перерисовки отображения.


Состояние


Но каков жизненный цикл DOM? Помимо редактора, его может менять и логика.


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



Дополнительно усложняет задачу то, что новое состояние может полностью изменить интерфейс, а в купе с практически бесконечной комбинаторикой вариантов изменения состояний, эта задача выглядит и вовсе решаемой только на уровне семантического аппарата, сравнимого с человеческим (да и человеческий не всегда справляется).


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


  1. Редактор;
  2. Предпросмотр.

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


Что же касается остальных, то я бы разделил их на 2 типа состояний:


  1. Ручные, те что может понять редактор и дать над ними контроль;
  2. Автоматические, непонятные редакторому, управляемые программно.

Отличным примером ручных будет Pagedraw с его редактором состояний и переходом между ними.


Но всё таки данная темя является одной из самых сложных, и требует гораздо более глубокие и тщательные исследования.


Резюме


Из вышеописанного складывается следующий концеп:


Мы можем взаимодействовать в режиме редактирования с блоками, которые представляют реальную значимость. Эти блоки могу формировать компоненты, которые в свою очередь могут иметь простые или сложные состояния.


Редактирование же состояний является отдельной задачей и может быть осуществлено как визуально, так и через код. Компоненты же формирую библиотеку. Это всё будет накладывать определенные правила и ограничения.


Проверка концепции


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


Код же выступает источником правды и хранит данные репрезентации, мета информацию, и структуру (контейнер-потомок).


Последующие же открытие кода восстанавливает состояние визуального редактора.


Вооружившись данным знанием, реализуем это в коде.


Ограничения


  1. Значимыми элементами считаются те, у кого есть класс или идентификатор;
  2. К элементам не применяются сторонние эффекты;
  3. Идентификатор является уникальным, повторное использование приведёт к неожиданным последствиям;
  4. Большинство крайних случаем не рассмотрены;
  5. Ошибки ожидаемы;
  6. Компоненты и состояни не реализованы;
  7. Код в HTML формате.
  8. Передвижение контейнера с потомками возможно при "захвате" пустого места


Вывод


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


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


Что дальше?


У меня есть ещё месяц свободного времени, так что достаточно игры в "кубики", пришло время реализовать чистовую модель редактора. Для начала, в качестве целевого стека, буду использовать React, а точнее JSX + styled-components, как наиболее используемый и изученный.


Данный процесс может занять довольно длительное время, понимая это, я смахнул пыль со своего twitter аккаунта и приглашаю всех заинтересованных следить за процессом, там я буде постить свои мысли о проблеме и текущее состояние работы, а если сойдутся звёзды, то и на результат свободный редактор для всех, чтобы "сдвинуть это веб".


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


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


Всем мир!

Подробнее..
Категории: Html , Javascript , Css , Html5 , Nocode , Html-верстка , Lowcode , Pix2html , Editor

Перевод Нововведения CSS Июль 2020 (Gap, Aspect ratio, Masonry, Subgrid)

31.07.2020 20:21:00 | Автор: admin

Приветствую. Представляю вашему вниманию перевод статьи CSS News July 2020, опубликованной 7 июля 2020 года автором Rachel Andrew



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


Gap для Flexbox


Давайте начнём с того, что уже реализовано в релизной версии одного браузера и бета-версиях других браузеров.


На момент перевода статьи поддерживается всеми современными браузерами (насчёт Safari точно неизвестно)

В CSS Grid мы можем использовать свойства gap, column-gap и row-gap для определения отступов между рядами, колонками или и тем и другим одновременно. Свойство column-gap также встречается в Мультиколонках для создания отступов между этими самыми колонками.


Хотя для создания отступов между grid-элементами можно использовать margin, плюсом свойства gap является то, что вы получаете отступы только между элементами, отступы от края grid-контейнера при этом не образуются. До сих пор для создания отступов между flex-элементами мы, как раз, и использовали margin. При этом, чтобы не допустить появления отступов от края flex-контейнера, приходилось применять к нему отрицательные margin.


Было бы неплохо иметь такое же свойство gap и для Flexbox, не так ли? Хорошая новость в том, что это произошло его поддержка уже реализована в Firefox и Chrome.


В следующем CodePen вы можете увидеть все три варианта. В первом варианте flex-элементы используют margin с каждой стороны. Это создаёт отступ в начале и в конце flex-контейнера. Во втором варианте для flex-контейнера используется отрицательный margin, чтобы вытащить этот выступающий margin за пределы границ контейнера. В третьем примере margin не используются, а вместо них задаётся gap: 20px, создающий отступ только между элементами.



Mind the Gap


Реализация gap для Flexbox выделяет несколько интересных моментов. Во-первых, как вы можете помнить, когда функционал отступов был впервые представлен в Grid Layout, были свойства:


  • grid-gap
  • grid-row-gap
  • grid-column-gap

Эти свойства были доступны сразу, как только браузеры получили поддержку CSS Grid. Но как свойства выравнивания (justify-content, align-content, align-items) сначала появились в Flexbox, а потом стали доступны в Grid, так и свойства gap со временем были переименованы и стали доступны не только в CSS Grid.


Вместе со свойствами выравнивания, свойства gap теперь относятся к спецификации "Box Alignment". Данная спецификация работает с выравниванием и распределением пространства, поэтому является лучшим местом для них. Чтобы уберечь нас от получения множества свойств, с префиксами из каждой спецификации, они также были переименованы, чтобы избавиться от префикса "grid".


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


Проверка поддержки свойств "gap" для Flexbox


Вы могли подумать, что можете свободно применять свойства "gap" для Flexbox, а для проверки наличия его поддержки использовать функциональные запросы "Feature Queries" с фолбэком с использованием "margin". К сожалению, это не так, поскольку функциональные запросы проверяют имя и значение. Например, если я хочу проверить наличие поддержки CSS Grid, я могу использовать следующий запрос:


@supports (display: grid) {  .grid {    /* grid layout code here */  }}

При проверке же поддержки свойства gap: 20px, я бы получила положительный ответ от Chrome, который на момент составления статьи не поддерживал "gap" в Flexbox, но поддерживал в CSS Grid. Всё, что делают функциональные запросы, так это проверяют, распознаёт ли браузер свойство и значение. У них нет возможности проверить наличие поддержки данного свойства в режиме раскладки Flexbox. Я подняла этот вопрос как проблему в рабочей группе CSS, однако это оказалось не так просто исправить.


Соотношение сторон


Порой нам хочется, чтобы даже при адаптивном изменении размеров, элемент сохранял фиксированное соотношение сторон. Например, в случае с изображениями или видео. Если вы размещаете на странице изображения или видео непосредственно с помощью HTML-тегов img или video, они по умолчанию сохраняют изначально присущее им соотношение сторон (если только вы принудительно не измените ширину или высоту). Однако, порой нам нужно добавить элемент, у которого одна сторона гибко заполняет доступное пространство, а другая изменяется исходя из заданного соотношения сторон. Чаще всего это применяется при встраивании в разметку видео через фрейм, однако помимо этого, вы можете захотеть сделать, например, идеальные квадратные области на сетке (или что-то другое, что требует, чтобы размер одной стороны изменялся в зависимости от изменения размера другой).


В данный момент для задания подобного поведения мы используем приём с padding, который основывается на том, что при использовании процентов, размер верхнего и нижнего "padding" элемента рассчитывается исходя из его ширины. Это не самое элегантное решение проблемы, но оно работает.


Новое свойство "aspect-ratio" решает эту задачу, позволяя нам указать необходимое соотношение сторон элемента. Chrome реализовал это в версии "Canary", поэтому вы можете увидеть пример работы данного функционала, если активируете флаг "Experimental Web Platform Features".


Я создала grid-раскладку и задала элементам сетки соотношение сторон "1 / 1". Ширина элементов определяется шириной их колоночного трека. Высота рассчитывается из ширины, чтобы образовать квадрат. Затем я добавила небольшой поворот.



В Chrome Canary можно ознакомиться с демо, чтобы увидеть, как даже при увеличении или сужении трека, элементы остаются квадратными благодаря тому, что их высота рассчитывается в пропорции "1 / 1" по отношению к ширине.



Встроенная поддержка Masonry


Разработчики часто спрашивают, может ли CSS Grid использоваться для создания Masonry или Pinterest-подобного макета. Хотя некоторые демо с разметкой, созданной с помощью CSS Grid, и похожи на подобные решения, данная технология разрабатывалась не для создания Masonry сеток.


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


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


Так может ли CSS Grid использоваться для создания Masonry сетки? Один из инженеров Mozilla считает, что может и создал прототип такого функционала. Вы можете попробовать его с помощью Firefox Nightly, в разделе по URL-адресу about:config установив флаг layout.css.grid-template-masonry-value.enabled, на значение true.




Хотя это может быть очень востребованным для всех, кто создавал такой тип разметки с помощью JavaScript, многие из нас задаются вопросом, является спецификация CSS Grid подходящим местом для определения этого очень специфичного функционала. Вы можете ознакомиться с моими размышлениями по этому поводу в статье "Does Masonry Belong In The CSS Grid Specification?".


Subgrid


Мы уже слышали раньше о начале поддержки значения subgrid в свойствах grid-template-columns и grid-template-rows в браузере Firefox. Использование этого значение подразумевает, что дочерние сетки могут наследовать размер и количество треков от сетки родительской. То есть, если элемент имеет свойство display: grid он может наследовать структуру строк и столбцов, которые он занимает на родительской сетке.


С данным функционалом можно ознакомиться в браузере Firefox. Также, у меня есть множество примеров, которые можно попробовать реализовать. Статья "Digging Into The Display Property: Grids All The Way Down" объясняет, чем Subgrid отличается от вложенных Grid-сеток, а "CSS Grid Level 2: Here Comes Subgrid" является введением в спецификацию. Также, у меня есть несколько примеров в Grid by Example.


Тем не менее, первый вопрос, который люди задают, когда говорю о Subgrid "Когда он станет доступен в Chrome?". Я всё ещё не могу сказать, когда именно, но некоторые первые новости уже видны в самом ближайшем будущем. 18 июня в блоке Chromium я анонсировала, что команда Microsoft Edge (в данный момент работающая над Chromium) перерабатывает Grid Layout в движок LayoutNG (движок следующего поколения для браузера Chromium). Часть этой работы также будет включать внедрение поддержки Subgrid.


Добавление функционала в браузер процесс не быстрый, однако именно команда Microsoft первой реализовала поддержку CSS Grid в виде ранней реализации в IE10. Так что это отличные новости и с нетерпением жду возможности протестировать бета-версию.


prefers-reduced-data


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


@media (prefers-reduced-data: reduce) {  .image {    background-image: url("images/placeholder.jpg");  }}

Медиа-запрос "prefers_reduced_data" работает так же, как некоторые уже реализованные в 5 уровне Спецификации медиа-запросов свойства, определяющие предпочтения пользователя. Например, медиа-запросы "prefers_reduced_motion" и "prefers_color_scheme" позволяют вам узнать, предпочитает ли пользователь уменьшить количество анимаций на сайте или может использует тёмную тему во всей операционной системе и соответствующим образом настроить CSS.


::marker


Псевдоэлемент "::marker" позволяет нам работать с маркером конкретного элемента списка. В самом простом случае это значит, что мы можем поменять его цвет или размер. Раньше это было невозможно из-за того, что можно было работать только со всем списком целиком.



В дополнение к стилизации маркеров настоящих списков, "::marker" можно использовать и для других элементов, списками не являющимися. В примере ниже у меня есть заголовок, которому присвоено свойство "display: list-item" и следовательно имеет маркер, который я заменила на emoji.


"::marker" уже браузером Firefox и в Chrome Canary.



Примечание: прочитать больше про псевдоэлемент "::marker" и другие связанные со списками функции можно в моей статье CSS Lists, Markers, And Counters


Пожалуйста, тестируйте новые функции


Я рекомендую пробовать применять новый функционал, если вам встречаются подходящие ситуации. Вы можете найти ошибку или что-то, что работает не так, как вы ожидали. Разработчики браузеров и Рабочая группа CSS с удовольствием хотели бы узнать о них. Если кажется, что вы нашли ошибку в работе браузера, например, заметили, что "::marker" в Chrome и Firefox ведёт себя по-разному, зафиксируйте эту проблему (в статье How to file a good browser bug описывается, как лучше это сделать). Если вы считаете, что в спецификации следовало бы предусмотреть обработку ещё какого-то поведение, также зафиксируйте это как проблему в GitHub-репозитории рабочей группы CSS

Подробнее..

Дайджест свежих материалов из мира фронтенда за последнюю неделю 426 (27 июля 2 августа 2020)

03.08.2020 00:21:10 | Автор: admin
Предлагаем вашему вниманию подборку с ссылками на новые материалы из области фронтенда и около него.


Медиа|Веб-разработка|CSS|JavaScript



Медиа


podcast Подкаст Фронтенд Юность (18+) #148: Vue, React, Svelte, Typescript, PWA
podcast Подкаст CSSSR: Vue 3 RC, релизы NodeJS, Svelte + TS, TSDX, V8 8.5, JS будущего, результаты опроса от JetBrains
podcast Подкаст Сделайте мне красиво, Выпуск 39: Привет, Svelte! Пока, moment.js!

Веб-разработка


habr Хватить это верстать дважды или 2-х сторонняя связь между дизайном и кодом
habr Локальное хранилище или куки? Безопасное хранение JWT на клиенте
habr О роли фронтенд-разработчика
Предстоящие изменения в WordPress 5.5, про которые должны знать разработчики тем
Подготовка к mobile-first-индексации с учетом дополнительного времени
en Ренессанс No-Code для веб-разработчиков
en this vs that: объяснение разницы между похожими понятиями в веб-разработке
en Визуализация работы CORS





CSS


habr Нововведения CSS Июль 2020 (Gap, Aspect ratio, Masonry, Subgrid)
habr CSS и множественный фон
habr Визуальное сравнение 13 CSS-фреймворков
Генератор цветовых тем
en Получение максимальной выгоды от вариативных шрифтов в Google Fonts
en Анализ CSS с помощью CSS OM: Получение поддерживаемых свойств, сокращений и других деталей
en PostCSS плагин для исправления бага с 100vh в iOS
en Что означает 100% в CSS?
en Несколько CSS комиксов
en Использование CSS для обнаружения и переключения тем сайта в соответствии с системными настройками
en Хотите стать лучше в написании кода? Научите кого-нибудь CSS.
en Жирный текст при наведении без сдвигов контента
en Почему CSS Grid Layout не заменит сетку фреймворка


JavaScript


habr Пишем свой dependency free WebSocket сервер на Node.js
en style9: компилятор CSS-in-JS, основанный на идеях stylex от Facebook
en Внедрение современного JavaScript в библиотеки
en Хватит дублировать константы в JS и CSS
en Разработка и развертывание микро-фронтендов с Single-Spa








Браузеры


habr Chrome (чуть не) снёс расширение, над которым мы работали три года, и не хочет говорить за что
Релиз Firefox 79, подробности для веб-разработчиков от Марата Таналина
Защищённые браузеры: выбираем лучший
Новый браузер Microsoft Edge аварийно завершал работу, если поисковиком по умолчанию в нём был установлен Google
Android-версия Chrome позволит подтверждать платежи с помощью биометрической аутентификации


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



Дайджест за прошлую неделю.
Материал подготовили dersmoll и alekskorovin.
Подробнее..

Из песочницы Медиазапросы в SCSS ещё один удобный способ использования media screen

03.08.2020 20:12:09 | Автор: admin
Привет!

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

В общем, для удобства составила себе такие требования:

  1. Размеры экранов должны быть вынесены отдельно, чтобы можно было глобально в одном месте поменять поведение (например, вместо 320px передавать просто xs).
  2. Данный миксин с медиазапросами может быть не только в одну сторону (например, не всегда только max-width).
  3. Миксин может использоваться и отдельно, переопределяя описанные классы внутри, или описываться в теле родителя, переопределяя его свойства.

Итак, определим любые нужные нам разрешения. Например:

$sizes: ("xs":320px, "sm":576px, "md":768px, "lg":992px, "xl":1200px);

Для начала, напишем миксин, который бы принимал нужный префикс диапазона и разрешение, под которое мы ограничиваемся:

@mixin media($minmax, $media) {  @each $size, $resolution in $sizes {    @if $media == $size {      @media only screen and (#{$minmax}-width: $resolution) {        @content;      }    }  }}

Если кратко, то мы передаём нужное нам название разрешения экрана, ищем его значение среди объявленных ранее в переменной $sizes. После того, как нашли, подставляем его вместе с переданным min или max (переменная $minmax).

Пример использования, включая в другой миксин:

@mixin blocks-width {  width: 400px;  @include media("max", "md") {    width: 100%;  }}

С этого простого примера мы получим миксин, меняющий ширину блока на разрешении <768px с 400px на 100%. Следующие примеры должны выдать такой же результат.

Пример использования внутри класса:

.blocks-width {width: 400px;  @include media("max", "md") {    width: 100%;  }}

Пример использования в качестве отдельного медиазапроса:

.blocks-width {width: 400px;}@include media("max", "md") {.blocks-width {    width: 100%;}}

А что, если нужен медиазапрос в том числе и с чётким диапазоном (указать одно разрешение, в пределах которого будет работать медиазапрос)? Расширим немного наш миксин.

Лично мне удобно описывать разрешение следующим образом если нам нужен диапазон md, то мы берём размеры экрана между sm и md. Если мы хотим переписать миксин таким образом, чтобы мы передавали только одно разрешение, то нам придётся найти предыдущее значение из списка. Так как я не нашла какого-то метода, чтобы это сделать быстро, то пришлось написать функцию:

@function getPreviousSize($currentSize) {  $keys: map-keys($sizes);  $index: index($keys, $currentSize)-1;  $value: map-values($sizes);  @return nth($value, $index);}

Чтобы проверить, как она работает, используйте debug:

@debug getPreviousSize('md');

Далее, наш немного переделанный код:

@mixin media($minmax, $media) {  @each $size, $resolution in $sizes {    @if $media == $size {      @if ($minmax != "within") {        @media only screen and (#{$minmax}-width: $resolution) {          @content;        }      } @else {        @if (index(map-keys($sizes), $media) > 1) {          @media only screen and (min-width: getPreviousSize($media)) and (max-width: $resolution) {            @content;          }        } @else {          @media only screen and (max-width: $resolution) {            @content;          }        }      }    }  }}

Логика такая же, что касается предыдущего функционала. Но, если хотите применить медиазапрос только в диапазоне, например, md, то при вызове миксина напишите следующее:

@include media("within", "md") {  .blocks-width {    width: 100%;  }}

После чего мы увидим такой скомпилированный css:

@media only screen and (max-width: 768px) and (min-width: 576px).blocks-width {    width: 100%;}

При этом, если мы укажем самый маленький размер экрана (у нас это xs), например:

@include media("within", "xs") {  .blocks-width {    width: 100%;  }}

То получим диапазон от 0 до соответствующего наименьшего разрешения:

@media only screen and (max-width: 320px).blocks-widthh {    width: 100%;}

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

Спасибо за внимание!
Подробнее..
Категории: Html , Css , Scss , Медиазапросы

CSS Grid понятно для всех

05.08.2020 14:08:45 | Автор: admin

Что такое Grid?


Grid представляет собой пересекающийся набор горизонтальных и вертикальных линий один набор определяет столбцы, а другой строки. Элементы могут быть помещены в сетку, соответственно строкам и столбцам.

Поддержка браузерами


В 2020 году поддержка браузерами достигает 94 %



Grid контейнер


Мы создаем grid контейнер, объявляя display: grid или display: inline-grid на элементе. Как только мы это сделаем, все прямые дети этого элемента станут элементами сетки.

<body> <div class="row">  <div class="row__item header">   <h1>Header</h1>  </div>  <div class="row__item nav">   <h1>Navbar</h1>  </div>  <div class="row__item article">   <h1>Article</h1>  </div>  <div class="row__item ads">   <h1>Ads</h1>  </div> </div></body>

.row { display: grid; margin: auto; grid-template-rows: 60px 1fr ; grid-template-columns: 20% 1fr 15%; grid-gap: 10px; width: 1000px; height: 1000px; justify-items: center; justify-content: space-between; grid-template-areas: "header header header" "nav article ads"; }

grid-template-rows это CSS свойство, которое определяет названия линий и путь размера функции grid rows.

CSS свойство grid-row определяет с какой строки в макете сетки будет начинаться элемент, сколько строк будет занимать элемент, или на какой строке завершится элемент в макете сетки. Является сокращенным свойством для свойств grid-row-start и grid-row-end.

Свойство CSS grid-gap является сокращенным свойством для grid-row-gap и grid-column-gap, определяющего желоба между строками и столбцами сетки.

Свойство grid-template-areas определяет шаблон сетки ссылаясь на имена областей, которые заданы с помощью свойства grid-area.

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

С помощью свойства grid-area мы можем назначить каждой из этих областей свое собственное имя. Именование областей еще не создает никакого макета, однако теперь у нас есть именованные области, которые мы можем в нем использовать.

.header{grid-area: header;}.nav{grid-area: nav;}.article{grid-area: article;}.ads{grid-area: ads;}

Создаем шаблон сайта с CSS Grid:




Изменяем шаблон


Вы можете изменить шаблон просто перераспределив грид-области в grid-template-areas.

Таким образом, если мы сменим на это:

grid-template-areas: "nav header header" "nav article ads"; }

То в результате получим такой шаблон:



Гриды с медиа запросами


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

Это делает CSS Grid идеальным для медиа запросов. Мы можем просто переназначить значения в ASCII-графике и обернуть результат в конечный медиа запрос.

@media all and (max-width: 575px) {.row {grid-template-areas:"header""article""ads""nav";grid-template-rows: 80px 1fr 70px 1fr ;grid-template-columns: 1fr;}}

В результате получим:



Таким образом, все дело состоит в переназначении значений в свойстве grid-template-areas.

Заключение


В данной статье мы рассмотрели всего лишь верхушку CSS Grid Layout айсберга. Иногда сложно поверить своим глазам какие штуки удается сделать при помощи CSS Grid. Это разрыв всех шаблонов. И мне это нравится.

Я вам советую обратить внимание на данную спецификацию и потратить немного своего времени на ее изучение. Поверьте, в будущем вам это точно пригодится и не важно, пишете вы на React, Angular, Vue (вставьте свое). Gridы пришли надолго.
Подробнее..

Дайджест свежих материалов из мира фронтенда за последнюю неделю 427 (3 9 августа 2020)

10.08.2020 00:11:52 | Автор: admin
Предлагаем вашему вниманию подборку с ссылками на новые материалы из области фронтенда и около него.


Медиа|Веб-разработка|CSS|JavaScript|Браузеры



Медиа


podcast Подкаст Веб-стандарты 241. Сайд-подкасты, онлайн-события, новости браузеров, main вместо master, поиски эмпатии
podcast Подкаст CSSSR: Тестирование Vue-компонентов, roadmap разработки Github, релизы Angular, Next.js и git
podcast Подкаст Фронтенд Юность (18+) 149: Нагибабель топит ледники

Веб-разработка


habr Технологии фронтенд-разработки, на которые вы, возможно, не обратили внимания
habr Профессиональное применение инструментов разработчика Chrome: 13 советов
en Руководство по веб-разработке для новичков The no jargon guide Развертывание вашего первого сайта
en Релиз Emmet 2 для Sublime Text





CSS


habr CSS Grid понятно для всех
habr Медиазапросы в SCSS ещё один удобный способ использования @media screen
habr 6 мощных возможностей CSS, которые позволяют обойтись без JavaScript
en Drop-Shadow: недооцененный CSS фильтр
en Computed Values: больше, чем кажется на первый взгляд
en Легкое решение для Masonry на CSS Grid c фолбеком на JavaScript
en Углубляемся в детали свойства Flex
en Современные решения на CSS grid для большинства проблем с раскладкой
en Реализация реалистичного перелистывания страниц на CSS
en Оптимизация CSS для более быстрой загрузки страницы
en Интерактивный словарь CSS
en Больше контроля над CSS Borders с помощью background-image
en font-weight: 300 может быть вредным (и возможное решение с fontconfig)
en Супергеройский леайут объединение CSS Grid и CSS Shapes

JavaScript


habr Мои любимые трюки в JavaScript
en Node Modules в состоянии войны: почему CommonJS и ES Modules не могут работать вместе
en RxJS & Firebase 101
en Анонс нового веб-сайта для TypeScript
en Сравнение моделей реактивности React vs Vue vs Svelte vs MobX vs Solid
en 1Keys Как я сделал пианино всего в 1 КБ JavaScript









Браузеры


В Firefox началась активация защиты от отслеживания перемещений через редиректы
Новый Edge всем и каждому. Microsoft заблокировала возможность деинсталляции браузера из Windows 10
Рыночная доля Chrome и Edge продолжает расти, а Firefox теряет популярность


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



Дайджест за прошлую неделю.
Материал подготовили dersmoll и alekskorovin.
Подробнее..

Оптимизация производительности фронтенда. Часть 1. Critical Render Path

05.08.2020 16:23:28 | Автор: admin

Здравствуйте. Меня зовут Ник, я фронтенд разработчик (жидкие аплодисменты). Кроме того, что я пишу код, я преподаю в Школе программистов hh.ru.


Записи наших лекций от 2018-2019 учебного года можно посмотреть на youtube


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



Вот презентация для тех, кому неохота читать лонгрид, но при этом хочется иметь базовое представление о контенте.


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


  1. Зачем думать о производительности
  2. FMP, TTI + подробнее в докладе
  3. Critical render path, DOM, CSSOM, RenderTree
  4. Шаги по улучшению производительности первой загрузки + подробнее в докладе

Для удобства восприятия я решил разделить статью на две части. Вторая часть будет о таких операциях, как layout, repaint, composite и их оптимизации.


Зачем вообще думать о производительности? Мотивационная часть


0.1 секунда это тот gap, который позволяет пользователю осознать, что именно его клик мышки, удар по клавиатуре побудил эти изменения в приложении\интерфейсе.
Кажется, у всех было то неловкое чувство, когда ты сочиняешь письмо\код\любой другой текст, а интерфейс "за тобой не успевает". Ты уже пишешь второе слово, а на экране всё еще песочные часы (если мы про windows) и еле-еле набирается первое. Аналогично и с кликами на кнопки. Я хочу, чтобы интерфейс мне подсказывал, мол, "окей, я тебя услышал, ща все будет".
За примером далеко ходить не нужно. Я пользуюсь веб-версией одного российского почтовика (не будем называть имен) и когда выделяю письма для их удаления, то бывают большие задержки. И я не понимаю: то ли я не попал по кнопке", то ли сайт тормознутый. И обычно верно второе.
Почему 0.1 секунда? Дело в том, что мы замечаем и успеваем обработать даже куда более ограниченные по времени изменения и наш мозг находится "в контексте".
В качестве яркого примера посмотрите клип 30 seconds to mars hurricane. Там есть вставки на кадр-два с текстом не 9:30. Глаз успевает не только осознать вставку, но и частично определить контент.


1 секунда идеальное время для загрузки сайта. В этому случае серфинг для пользователя воспринимается как что-то очень органичное. Если ваш ресурс готов к работе за 1 секунду вы большой молодец. Как правило, реальность другая.


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


Поэтому обычно 1 секунда это некий идеал, к которому нужно и можно стремиться, но и голову терять не нужно.


10 секунд если погуглить, на всякую аналитику вроде "среднее время пользователя на сайте" мы увидем число: 30 секунд. Сайт загружающийся 5 секунд убивает 1/6 времени пользователя. 10 секунд треть.


Дальше идут два числа 1 минута и 10 минут. первое идеальное время для того, чтобы пользователь выполнил небольшую задачу на сайте прочитал описание товара, зарегистрировался на сайте и т.д. Почему минута? В наши дни мы не так много тратим время на концентрацию на одной вещи. Как правило наше внимание очень быстро перескакивает с одного на другое. Открыл статью, прочитал десятую часть, дальше коллега мем в телегу отправил, тут триггер зажегся, новости про короновирус, верните мне мой 2007, вот это все. В общем к статье получится вернуться только через час.


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


Большие компании даже хорошую аналитику для таких целей имеют:


  • Walmart: 1 секунда ускорения + 2% конверсии
  • Amazon: 0,1 секунды увеличивает выручку на 1%
  • Что-то аналогичное есть у Яндекса (киньте в комментариях ссылку, я потерял)

И последний мотивационный пост в статье от википедии:



Однако достаточно вводной, пора двигаться дальше.


Два извечных вопроса


Давайте запустим lighthouse на hh.ru. Выглядит всё очень не очень (запуск на mobile, на desktop все сильно лучше):



Появляется два традиционных вопроса:


  1. Кто в этом виноват?
  2. Что с этим делать?

Хотя первый вопрос я бы заменил на "Как это расшифровать".
Сразу спойлер: картинки "как круто стало в конце не будет. Как сделать лучше мы знаем. Но есть определенные ограничения.


Давайте разбираться


В первом приближении у нас есть 3 потенциальных сценария:


  1. Отрисовка страницы (с html от сервера)
  2. Работа загруженной страницы (клики пользователя и т.д.)
  3. SPA переходы между страницами без перезагрузки

У пользователя существует два этапа при отрисовке страницы, когда он может частично взаимодействовать с сайтом. И полноценно: FMP (First Meaningful Paint) и TTI (Time to interactive), когда ресурсы загружены, а скрипты проинициализированы:



Если судить о значении для пользователя: FMP == текст, есть верстка и пользователь может начать потреблять контент (конечно, если вы не инстаграмм). TTI == сайт готов к работе. Скрипты загружены, проинициализированны, ресурсы загружены.


Подробнее о расчетах FMP\TTI и как мониторить эту информацию на своем сайте, снимая данные с реальных людей, я рассказывал на РИТ++. В этом же докладе я говорил и про эксперименты, которые мы проводили по ускорению и замедлению скорости работы сайта.


Наиболее важный показатель для нас FMP. Соискатели открывают поиск, затем накликивают "открыть в новой вкладке" большое количество вакансий, а затем читают и принимают решение об отклике. C некоторыми оговорками (нюансы рендера браузера) FMP можно воспринимать как одну из основных метрик, которая описывает Critical render path. Critical render path это набор действий и ресурсов, которые браузер должен совершить, загрузить и обработать, чтобы пользователь получил свой первый результат, пригодный для работы. То есть это минимальный набор html, css и блокирующие скрипты (если так еще кто-то делает), без которых сайт не отобразится пользователю.


Critical render path или что браузер делает для того, чтобы пользователь увидел тот самый текст?


TL&DR;


  1. Сделать запрос (DNS resolve, TCP поход и т.п.);
  2. Получить HTML-документ;
  3. Провести парсинг HTML на предмет включенных ресурсов;
  4. Построить DOM tree (document object model);
  5. Отправить запросы критических ресурсов. CSS, блокирующий JS (параллельно с предыдущим пунктом);
  6. Получить весь CSS-код (также запускаем запросы на JS-файлы);
  7. Построить CSSOM tree;
  8. Выполнить весь полученный JS-код. Здесь могут вызываться layout, если из js кода происходит форсирование reflow;
  9. Перестроить DOM tree (при необходимости);
  10. Построить Render tree;
  11. Отрисовать страницу (layout paint Composite).

Теперь пройдемся по пунктам отдельно:


Подробно:


Request



Формируем запрос, резолвим DNS, IP, TCP поход, передача запроса и т.п. Байтики бегают по сокетам, сервер получил запрос.


Response


Бекенды зашумели вентиляторами, обработали запрос, записали обратно данные в сокет и нам пришел ответ. Например, вот такой:



Мы получили байты, сформировали из нее строку, основываясь на данных text/html, и после пометки нашего запрос как "navigate" (кому интересно это можно посмотреть в ServiceWorker) браузер должен сформировать из этого html DOM.


Сказано, сделано:


Обработка DOM


DOM


Мы получаем строку или поток данных. На этом этапе браузер парсит и превращает полученную строку в объект:



Это только каркас. Сейчас браузер ничего не знает про стили и про то, каким образом всё это рендерить.


Загрузка блокирующих ресурсов


Браузер будет последовательно обрабатывать полученный html и каждый ресурс. CSS, JS может быть загружен как синхронно, блокируя дальнейшую обработку DOM, так и асинхронно (для css это способ с preload + сменой rel после загрузки на stylesheet). Поэтому каждый раз, когда браузер будет встречать блокирующую загрузку стилей или JS, он будет формировать запрос за этим ресурсом.
Для каждого такого ресурса повторяем путь с запросом, ответом, парсингом ответа. Здесь появляются ограничения, например, количество одновременных запросов на домен. Предположим, что все блокирующие запросы были описаны внутри тега head, браузер сделал запросы, получил нужные для рендера стили. После формирования DOM переходим к следующему этапу:


CSSOM


Предположим, что помимо meta и title был тег style (либо link). На данном этапе браузер берет DOM, берет CSS, собирает соответствия, и на выходе мы получаем объектную модель для CSS. Выглядит это примерно так:



Левая часть (head) для CSSOM практически не интересна, она не отображается пользователю. А для остальных узлов мы определили стили, которые браузеру нужно применить.


CSSOM важен, так как его понимание позволяет браузеру сформировать RenderTree.


RenderTree


Последний шаг на этапе от формирования деревьев к рендеру.


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



То есть, именно это дерево мы и отрендерим. Почему его? Если мы зайдем в DevTools там отображается DOM". Дело в том, что, хоть в DevTools и присутствуют все DOM элементы, все расчеты и вычисленные свойства уже основаны на RenderTree.


Проверить крайне легко:



Здесь мы выделили кнопку во вкладке Elements. Мы получили всю "вычисленную" информацию. Её размеры, положение, стили, наследование стилей и т.д.
Когда мы получили RenderTree, наша следующая задача выполнить Layout Paint Composite нашего приложения. После этих трех этапов пользователь и увидит наш сайт.
Layout Paint Composite могут быть болью не только во время первого рендера, но и при работе пользователя с сайтом. Поэтому мы разберем их во второй части статьи.


Что можно сделать, чтобы улучшить метрики FMP и TTI?


TL&DR;


1) Работа с ресурсами:


1.1) Разнести блокирующие ресурсы по страницам. Как js, так и css. Хранить реиспользуемый между страницами код либо в отдельных бандлах, либо в отдельных небольших модулях.


1.2) Грузить то, что пользователю нужно в начале работы со страницей (очень спорный момент!)


1.3) Вынести third-party скрипты


1.4) Грузить картинки лениво


2) HTTP2.0 / HTTP3.0:


2.1) мультиплексинг


2.2) сжатие заголовков


2.3) Server push


3) Brotli


4) Кэш, ETag + Service worker


Подробно:


Работа с ресурсами


Разносим блокирующие ресурсы. JS


Основной болью являются 2 вещи: блокирующие ресурсы и размер этих ресурсов.
Самый главный совет для больших сайтов это разнести блокирующие стили, ресурсы по страницам. Реиспользумый код выносить в отдельные бандлы или модули. Для этого можно воспользоваться условным loadable-components или react-imported-component для реакта и похожими решениями для vue и т.д. Если наши компоненты импортируют стили, то мы сможем также и разбить стили на отдельные страницы.
На выходе мы получаем:


  1. бандлы с реиспользуемыми JS модулями
  2. страничные бандлы.

Стратегией по разбиению кода можно легко управлять. Можно как создавать бандлы, которые объединяют код для нескольких страниц, так и просто страничные и общие. Лучше всего разницу можно посмотреть на схемах.


Изначальная расстановка:



Стратегия 1: делаем зависимость модуль страницы, которые используют модуль



Так, чтобы загрузить главную страницу (index.html), нам нужно будет загрузить 2 бандла: Common.JS + applicant+index.JS, а для страницы /applicant нужно загрузить все 4 бандла. На больших сайтах таких модулей может быть очень много. В этом случае нам помогает решить эту проблему использование HTTP2.0.


Итого:
+: Данные распределены между страницами, мы грузим всегда только необходимое
+: Модули легко кэшируются, после релиза не обязательно обновлять все бандлы у пользователя
-: Много сетевых издержек для получения отдельных ресурсов. Фиксим с помощью мультиплексирования HTTP2.0.


Стратегия 2: реиспользуемые модули хранятся отдельно:



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


+: Во время релизов большая часть модулей останется в кэше у пользователя
-: Еще больший рост сетевых издержек, если у пользователя нет HTTP2.0
-: Кэши могут не работать, так как файлы будут меньше 1 Кб. Здесь нас может спасти Service worker. О нем будет ниже.


Эта стратегия имеет право на жизнь, так как минусы решаемы.


Стратегия 3: Иметь большой бандл реиспользуемого кода:



+: малое количество бандлов. Для загрузки страницы нужен страничный JS + Common.JS
-: При первой загрузке мы получаем очень много unused JS
-: При релизе скорее всего пользователю придется скачивать общий бандл заново, преимущество кэшей теряется.


Я бы рекомендовал либо не использовать этот вариант вообще, либо использовать его для небольших сайтов.


Анти-Стратегия 1: Каждая страница хранит весь список зависимостей, выносим только common:



В данном случае мы получаем большой оверхед. При переходе с одного ресурса на другой пользователь закачивает себе модули, которые уже у него были несколько раз. Например, пользователь заходит на главную и скачивает 2 бандла: Common.JS и Index.JS затем авторизуется и попадает на страницу соискателя. Итого, код для Dropdown.JS и Graph.JS будет скачан дважды.


Пожалуйста, не делайте так :)


Итого


Для больших сайтов я бы рекомендовал использовать одну из первых двух стратегий. Скорее всего это улучшение положительно скажется на вашей TTI метрике. Если же у вас блокирующий JS, то стоит задаться вопросом почему. Должен ли он быть таким? Старайтесь держать как можно меньше блокирующего JS на странице.


Оффтоп. Почему 30 Кб JS это больнее, чем 30 Кб картинки


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


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


Итого, на обработку JS кода мы тратим больше времени, чем на ту же картинку.


Разносим блокирующие ресурсы. CSS


Данное улучшение напрямую влияет на FMP, если у вас не асинхронный CSS.
Если вы используете react\vue\angular, то для стилей стоит сделать то же, что и в предыдущем пункте. Как правило, в том же react-коде мы имеем импорты вида:


import './styles.css'

Это значит, что во время бандлинга JS-кода мы можем разделить и CSS, воспользовавшись одной из стратегий выше. Это поможет вебпаку или другому бандлеру получить аналогичные common.css, applicant-page.css и applicant+employer.css.
Если разбить используемый CSS не получается, можно посмотреть в сторону used-styles и статью на эту тему: "optimising css delivery". kashey спасибо за клевые инструменты :)


Это поможет ускорить загрузку, например в случае с hh.ru почти на секунду по эстимейтам lighthouse:



Грузим то, что увидит пользователь, а не всю страницу.


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


Идея данной оптимизации в том, чтобы управлять загрузкой ваших ресурсов. В начале загрузить блокирующим способом тот CSS, который жизненно необходим для открытия страницы. Весь CSS, который относится к всплывающим элементам, popup-ам, которые спрятаны под JS кодом можно будет грузить асинхронно, например, добавив rel=stylesheet уже из JS кода, либо воспользовавшись prefetch с onload колбеком.


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


Выносим third-party скрипты


У нас в hh их много. Очень много!
Например? здесь в ТОП-10 самых тяжелых скриптов 7 third-party.



Что мы можем с этим сделать?


  1. Убедиться, что все ресурсы грузятся асинхронно и не влияют на FMP.
  2. Для рекламы и прочих вещей (излишней аналитики, popup-ов поддержки) снизить их влияние на основной "полезный" код. Это можно сделать, начав их инициализировать из нашего кода по requestIdleCallback. Эта функция запланирует вызов колбека с низшим приоритетом, когда наш браузер будет простаивать.

Такой подход позволяет нам экономить на FMP, хотя в TTI мы по-прежнему будем наблюдать проблемы. Это также поможет нам отложить работу прожорливых third-part скриптов.


Грузим картинки лениво


Картинки влияют на ваш TTI. Если вы понимаете, что пользователи из-за лишней работы браузера могут страдать, попробуйте начать грузить картинки, которые не попадают на экран, лениво. То есть:


  1. Картинки попадающие на первый экран, грузим как обычно
  2. Оставшимся картинкам проставляем специальные атрибуты, чтобы изображение грузилось только по мере того, как пользователь проскроллит к нему
  3. Используем любую библиотеку\велосипед для ленивой загрузки картинок. Вот здесь достаточно хорошо описан подход.

HTTP2.0


Многие из пунктов HTTP2.0 могут не сэкономить заметного количества времени, но разобрать их стоит.


HTTP2.0 Мультиплексинг


В случае если сайт загружает большое количество ресурсов, HTTP2.0 с мультиплексингом может сильно помочь.
Предположим, у нас есть 6 блокирующих ресурсов на домене, которые нужно скачать, чтобы отобразить сайт. Это могут быть стили или блокирующий JS. Считаем, что пользователь уже загрузил HTML:



Для отображения контента браузер будет производить параллельные запросы к каждому ресурсу:



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


Кроме того, каждый из ресурсов будет проходить времязатратные этапы на TCP handshake и прочие издержки. Они небольшие, но все-таки присутствуют.


Именно поэтому совет нужен бандлинг и отдавать пользователю один бандл с нужным ему на этой странице CSS \ JS картинками работает.


Что такое мультиплексирование?


Мультиплексирование позволяет нам грузить ресурсы внутри одного HTTP запроса:



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


HTTP2.0 Сжатие заголовков


До http2.0 сжатия заголовков не существовало. В HTTP2.0 был анонсирован HPACK, которые отвечает за сжатие. Здесь можно почитать подробнее.


Иногда заголовки могут занимать значительный объем запроса. О том, как работает сжатие заголовков HPACK вкратце:


Используется два словаря:


  1. Статический для базовых заголовков
  2. Динамический для кастомных

Для префиксного кодирования используется Huffman coding. На практике эта экономия выходит не сильно высокой и малозаметной.


HTTP2.0 Server push


В базовом варианте server push реализовать несложно. Проще всего сделать такую штуку для статических сайтов. Идея простая: вместе с запросом html страницы, наш веб-сервер заранее знает, что пользователю нужно отдать такой-то css, такую-то картинку и такой-то JS.


Реализуется достаточно просто (nginx):


location = /index.html {    http2_push /style.css;    http2_push /bundle.JS;    http2_push /image.jpg;  }

Проверить, что все работает несложно:



Такой способ будет работать для небольших статических сайтов. Если у вас большой сайт, то придется настраивать сложный пайп-лайн. Когда после сборки имена ваших ресурсов записываются в какой-то словарь, который затем собирает конфиг для nginx, содержащий урлы и прописывает http2_push правила.


Сжатие данных


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



Примерно полтора года назад мы в hh.ru перешли с gzip на бротли. Размер нашего основного бандла уменьшился с 736 КБ до 657. Выиграли почти 12%.


Главным недостатком Brotli можно назвать затраты на "упаковку" данных. В среднем она тяжелее, чем gzip. Поэтому на nginx можно указать правило, чтобы он паковал ресурс и складывал его рядом, дабы не делать сжатие на каждый запрос. Ну или при сборке сразу класть сжатый вариант. Аналогично можно делать и для gzip.


Но в любом случае Brotli ваш бро! На сайтах среднего размера он позволяет сэкономить секунду-полторы загрузки на слабых 3G сетях, что сильно улучшает как пользовательские ощущения, так и метрики в том же lighthouse.


КЭШ


Примечание: описанный здесь способ не поможет вам получить дополнительные баллы у lighthouse, но поможет при работе с реальными пользователями. Этот способ положительно сказывается как на FMP, так и на TTI.
Сам кэш можно включить либо с помощью заголовков у статики, либо с помощью Service Worker.
Если мы говорим о заголовках, для этого служит 3 основных параметра:


  1. last-modified или expires
  2. ETag
  3. Cache-control

Первые два (last-modified и expires) работают по дате, второй ETag это ключ, который используется при запросе и если ключи совпадают, сервер ответит 304 кодом. Если не совпадут, то сервер отправит нужный ресурс. Включается на Nginx очень просто:


location ~* ^.+\.(js|css)$ {            ...    etag on;}

Disk cache проверяется очень просто через dev tools:



Cache-control это стратегия того, как мы будем кэшировать информацию. Мы можем или отключить его вовсе, установив cache-control: no-cache, что может быть полезным для html запросов, которые часто меняются. Либо мы можем указать очень большой max-age, чтобы данные хранились как можно дольше. Для нашей статики, мы устанавливаем вот такой Cache-control:


cache-control: max-age=315360000, public

У нас частые релизы (несколько раз в день релизим каждый сервис), поэтому код в основном бандле меняется часто. Это приводит к тому, что пользователям приходится часто скачивать наши бандлы, парсить код и т.д.
Чтобы больше разобраться в том, как современные браузеры исполняют код и используют кэши, можно почитать прекрасную статью в блоге v8
Нам интересна вот эта иллюстрация:



У нас есть "три способа" запуска нашего приложения: cold\warm и hot run. Идеально, если мы будем запускать приложение в режиме hot run, потому что на этом этапе мы не тратим время на компиляцию нашего года. Его достаточно только десериализовать.


Для того, чтобы получить hot run, пользователю нужно зайти на сайт в третий раз (за одними и теми же ресурсами) в таймслоте в 72 часа. В третий потому что во второй раз будет выполнен warm run, который будет компилировать и сериализовать данные в дисковый кэш.


Мы на самом деле можем зафорсить hot run, использовав Service Worker. Механизм следующий:


  1. Устанавливаем пользователю Service Worker;
  2. Service worker подписывается на fetch;
  3. Если происходит fetch за статикой, то сохраняем результат в кэш;
  4. Добавляем перед отправкой запроса проверку на наличие ресурса в кэше.

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


Минимальный вариант кода для данного случая:


self.addEventListener('fetch', function(event) {        // Кешируем статику, но не картинки    if (event.request.url.indexOf(staticHost) !== -1 && event.request.url.search(/\.(svg|png|jpeg|jpg|gif)/) === -1) {        return event.respondWith(                        // проверяем наличие данных в кеше            caches.match(event.request).then(function(response) {                if (response) {                    return response;                }                                // Если данных в кеше нет, делаем запрос и сохраняем данные в кеш, который наызываем cacheStatic                return fetch(event.request).then(function(response) {                    caches.open(cacheStatic).then(function(cache) {                        cache.add(event.request.url);                    });                    return response;                });            })        );    }});

Итого


Мы рассмотрели наш Critical render path с точки зрения клиента (не углубляясь в такие вещи, как резолв DNS, handshake, запросы в БД и т.п.). Определили те шаги, которые делает браузер, чтобы сформировать первую страницу для пользователя. Поверхностно посмотрели на сложные способы оптимизации (разделения контента и т.д.)/ И разобрали более простые способы оптимизации: бандлинг, кэш, сжатие, транспорт.


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


Небольшое уточнение: здесь рассмотрены не все способы оптимизации, их заметно больше и появляются новые. Например, в chrome 85 появится свойство content-visibility, которое позволит сократить время на рендеринг за счет отложенных вычислений.

Подробнее..

Перевод Продуманный front-end. Правильная архитектура для быстрых сайтов

11.08.2020 10:19:42 | Автор: admin
Привет, Хабр!

Мы давно обходили вниманием темы браузеров, CSS и accessibility и решили вернуться к ней с переводом сегодняшнего обзорного материала (оригинал февраль 2020). Особенно интересует ваше мнение об упомянутой здесь технологии серверного рендеринга, а также о том, насколько назрела необходимость в полноценной книге по HTTP/2 впрочем, давайте обо всем по порядку.


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

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

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

Обзор

Разобьем процесс загрузки приложения на три отдельных этапа:

  1. Первичный рендеринг сколько времени пройдет, прежде, чем пользователь что-то увидит?
  2. Загрузка приложения сколько времени пройдет, прежде, чем пользователь увидит приложение?
  3. Следующая страница сколько времени требуется для перехода на следующую страницу?


Первичный рендеринг

До этапа первичного рендеринга (отрисовки) пользователю попросту ничего не увидеть. Чтобы отобразить страницу, нужен, как минимум, HTML-документ, но в большинстве случаев приходится загружать и дополнительные ресурсы, в частности, файлы CSS и JavaScript. Если они доступны, то браузер может начинать отрисовку на экране.

В этом посте я буду использовать каскадные диаграммы WebPageTest. Каскад запросов для вашего сайта будет выглядеть примерно так.



Вместе с HTML-документом загружается набор других файлов, и страница отображается после того, как они все они будут в оперативной памяти. Обратите внимание: загрузка CSS-файлов происходит параллельно, поэтому каждый следующий запрос не приводит к существенному увеличению задержки.

Сокращаем количество запросов, блокирующих рендеринг

Таблицы стилей и (по умолчанию) скриптовые элементы не позволяют отобразить какой-либо контент, расположенный под ними.

Существует несколько способов, позволяющих это исправить:

  • Ставим скриптовые теги в самом низу тега body
  • Асинхронно загружать скрипты при помощи async
  • Внутристрочно записывать небольшие фрагменты JS или CSS, если их требуется загружать синхронно


Избегайте образования цепочек запросов, блокирующих рендеринг

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

Если браузеру станет известно о необходимости загрузки файла только после того, как завершится другой запрос, то у вас может получиться цепочка синхронных запросов. Это может произойти по нескольким причинам:

  • Наличие правил @import в CSS
  • Использование веб-шрифтов, ссылки на которые стоят в CSS-файле
  • Ссылка для инъекции JavaScript или скриптовые теги


Рассмотрим такой пример:



В одном из CSS-файлов на этом сайте содержится правило @import, предназначенное для загрузки шрифта Google. Таким образом, браузер должен выполнять следующие запросы один за другим, в таком порядке:

  1. Document HTML
  2. Application CSS
  3. Google Fonts CSS
  4. Файл Google Font Woff (не показан в каскаде)


Чтобы это исправить, сначала переместим запрос к Google Fonts CSS из @import к ссылочному тегу в HTML-документе. Так мы укоротим цепочку на одно звено.

Чтобы добиться еще более значительного ускорения, встроим файл Google Fonts CSS прямо в ваш HTML или в ваш CSS-файл.

(Помните, что CSS-отклик от Google Fonts зависит от пользовательского агента. Если сделать запрос при помощи IE8, то CSS сошлется на файл EOT (внедряемый OpenType), IE11 получит woff-файл, а современные браузеры woff2. Но, если вас устраивает работать так, как со сравнительно старыми браузерами, использующими системные шрифты, то можно просто скопировать и вставить содержимое CSS-файла.)

Даже после того, как начнется рендеринг страницы, пользователь, возможно, ничего не сможет с ней поделать, так как не отобразится никакого текста до полной загрузки шрифта. Этого можно избежать при помощи свойства font-display swap, которое теперь используется в Google Fonts по умолчанию.

Иногда полностью избавиться от цепочки запросов не удается. В таких случаях попробуйте использовать тег preload или preconnect. Например, сайт, показанный выше, может подключиться к fonts.googleapis.com до того, как фактически будет сделан запрос к CSS.

Переиспользуем серверные соединения для ускорения запросов

Как правило, для установления нового серверного соединения требуется 3 прохода туда-обратно между браузером и сервером:

  1. Поиск DNS
  2. Установление TCP-соединения
  3. Установление SSL-соединения


Как только соединение установлено, требуется еще как минимум 1 проход туда и обратно: отправить запрос и загрузить отклик.

Как показано в нижеприведенном каскаде, соединения инициируются к четырем разным серверам: hostgator.com, optimizely.com, googletagmanager.com и googelapis.com.

Однако при последующих запросах к затронутому серверу можно заново пользоваться уже имеющимся соединением. Поэтому base.css или index1.css загружаются быстро, так как они тоже расположены на hostgator.com.



Уменьшаем размер файла и используем сети доставки контента (CDN)

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

Отправляйте пользователю минимально необходимое количество данных, причем, позаботьтесь об их сжатии (напр., при помощи brotli или gzip).

Сети доставки контента (CDN) предоставляют сервера, расположенные в самых разных местах, поэтому велика вероятность, что какой-нибудь из них будет расположен поблизости от ваших пользователей. Вы можете подключать их не к вашему центральному серверу приложений, а к ближайшему серверу в сети CDN. Таким образом, путь данных на сервер и обратно значительно сократится. Это особенно удобно при работе со статическими ресурсами, например, CSS, JavaScript и изображениями, поскольку их легко распределять.

Минуем сеть при помощи сервис-воркеров

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



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

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

self.addEventListener("install", async e => { caches.open("v1").then(function (cache) {   return cache.addAll(["/app", "/app.css"]); });});self.addEventListener("fetch", event => { event.respondWith(   caches.match(event.request).then(cachedResponse => {     return cachedResponse || fetch(event.request);   }) );});


О предзагрузке и кэшировании ресурсов при помощи сервис-воркеров подробнее рассказано в этом руководстве.

Загрузка приложения

Хорошо, наш пользователь уже что-то увидел. Что еще ему потребуется, чтобы он мог пользоваться нашим приложением?

  1. Загрузка приложения (JS и CSS)
  2. Загрузка наиболее важных данных для страницы
  3. Загрузка дополнительных данных и изображений




Обратите внимание: рендеринг может замедляться не только из-за загрузки данных по сети. Когда код будет загружен, браузеру потребуется разобрать, скомпилировать и выполнить его.

Разделение бандла: загружаем только необходимый код и доводим до максимума попадания в кэш

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

Как правило, код состоит из файлов трех различных типов:

  • Код, специфичный для данной страницы
  • Разделяемый код приложения
  • Сторонние модули, которые меняются редко (отлично подходят для кэширования!)


Webpack может автоматически разбивать разделяемый код, чтобы снизить общий вес загрузок, это делается при помощи optimization.splitChunks. Обязательно активируйте фрагмент, отвечающий за время исполнения (runtime chunk), так, чтобы хэши фрагментов оставались стабильными, и можно было с пользой применять долгосрочное кэширование. Иван Акулов написал подробное руководство о разделении и кэшировании кода Webpack.

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

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



Однако, в этом каскаде также показано 2 запроса, выполняемых последовательно. Эти фрагменты нужны только для данной страницы, и динамически загружаются при помощи вызова import().

Это можно исправить, вставив тег preload link, если вам известно, что эти фрагменты точно понадобятся.



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

Кроме того, использование предзагрузки иногда бывает контрпродуктивным и приводить к задержкам, когда загружаются другие, более важные файлы. Почитайте пост Энди Дэвиса о предзагрузке шрифтов и о том, как заблокировать первичный рендеринг, загрузив сначала шрифты, а потом уже CSS, препятствующие рендерингу.

Загрузка страничных данных

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

Не дожидайтесь бандлов, сразу начинайте загружать данные

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

Есть два способа этого избежать:

  1. Встраивать страничные данные в HTML-документ
  2. Начинать запрашивать данные через внутристрочный скрипт, находящийся внутри документа


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

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

В таком случае, либо при выдаче кэшированного HTML-документа при помощи сервис-воркера, можно встроить в HTML внутристрочный скрипт, который будет загружать эти данные. Его можно предоставить в виде глобального промиса, вот так:

window.userDataPromise = fetch("/me")


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

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

Не блокируйте рендеринг, пока дожидаетесь несущественных данных

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

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



Избегайте случаев, в которых возникают цепочки последовательных запросов к данным

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

Вместо того, чтобы сначала сделать запрос о том, что за пользователь вошел в систему, а потом запрашивать список групп, к которым относится этот пользователь, возвращайте список групп вместе с информацией о пользователе. Для этого можно использовать GraphQL, но собственная конечная точка user?includeTeams=true также отлично подойдет.

Рендеринг на стороне сервера

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

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

Используйте серверный рендеринг, если видите, что неинтерактивный контент ценен сам по себе. Также такой подход помогает кэшировать на сервере тот HTML, который был там отображен, после чего передавать его всем пользователям без задержки при первичном запросе документа. Например, серверный рендеринг отлично подойдет в случае, когда вы отображаете блог при помощи React.

Почитайте эту статью Михала Янашека; в ней хорошо описано, как комбинировать сервис-воркеры с рендерингом на стороне сервера.

Следующая страница

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

Предварительная выборка ресурсов

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

import(    /* webpackPrefetch: true, webpackChunkName: "todo-list" */ "./TodoList")


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

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

Переиспользуйте те данные, что уже загружены

Локально кэшируйте данные Ajax в вашем приложении, чтобы впоследствии обойтись без лишних запросов. Если пользователь переходит к списку групп на странице Редактировать группу, такой переход можно сделать мгновенным, повторно использовав данные, уже выбранные ранее.

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

Заключение

В этой статье мы рассмотрели ряд факторов, которые могут замедлять работу страницы на различных этапах процесса загрузки. Пользуйтесь такими инструментами как Chrome DevTools, WebPageTest и Lighthouse, чтобы определить, какие из советов актуальны в вашем приложении.

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

Работая над этой статьей, я осознал, что разделяю глубоко укоренившееся убеждение, будто множество отдельных запросов это плохо с точки зрения производительности. Это было актуально в прошлом, когда для каждого запроса требовалось отдельное соединение, а браузеры допускали лишь несколько соединений на домен. Но такая проблема исчезла с появлением HTTP/2 и современных браузеров.

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

В диких условиях. Итоги проектов Школы программистов в эпоху самоизоляции

12.08.2020 10:04:09 | Автор: admin
За четыре месяца занятий были прочитаны 54 лекции на двух потоках бекэнд и фронтенд, проведены несколько крутых практикумов с live-codingом. Проверены сотни заданий, на все вопросы получены две сотни ответов. Тут пришел 2020 год и сразу после того как мы сняли с елок гирлянды, всем нам самим пришлось нарядиться в маски и надеть перчатки. А теперь по порядку:



Десятая Школа Программистов hh.ru стала особенной. Юбилей, огромное количество планов, неиссякаемый поток учеников, неугасающая мотивация наших преподавателей и организаторов. Мы приложили максимум усилий, чтобы этот выпуск стал образцовым.

Десятая Школа Программистов hh.ru стала особенной. Юбилей, огромное количество планов, неиссякаемый поток учеников, неугасающая мотивация наших преподавателей и организаторов. Мы приложили максимум усилий, чтобы этот выпуск стал образцовым.

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

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

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

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

Сразу следует рассказать о цели проектов: за три месяца научить ребят реальной командной работе, пройти все шаги от планирования и организации инфраструктуры до работы над UX и создания полноценного MVP. Для этого каждой команде мы предложили по одной теме, которую поддержали менторы.

Вот эти темы:

  • Сервис по формированию коммерческих предложений для работодателей сервис поддержки наших salesов, который позволит работать эффективнее, а нашим клиентам получать действительно индивидуальные предложения;
  • Внутренний сервис для разработчиков, позволяющий геймифицировать процесс написания кода и создавать рейтинги разработчиков по различным критериям приложение должно общаться с нашим GitHub-аккаунтом и показывать данные о тех разработчиках, которые работают быстрее, выше и сильнее;
  • Сервис для оценки качества поисковой выдачи. Наверняка вы слышали /что в интернете кто-то не прав:)/, как кто-то жалуется на то, что в результатах поиска в интернете нашлась какая-то нерелевантная информация. Так вот, у нас на сайте hh.ru тоже так бывает. Чтобы это исправить, нужен сервис, который будет позволять оценивать, насколько поиск был успешным и насколько результаты соответствуют запросу;
  • Внутренний сервис для тимлидов и разработчиков по оценке навыков мы, как и многие технологические компании, поощряем развитие сотрудников и для рекомендаций и помощи тимлидам используем систему оценки навыков. Её MVP был реализован через google forms, но функциональности очень не хватало, поэтому решили сделать свою кастомную систему;
  • Сервис для тегирования вакансий. Сейчас в нашем приложении для вакансии и резюме можно указать ключевые навыки, которые являются приоритетными метками для поиска и сравнения. Их нужно проставлять вручную и не всегда это делают правильно. Цель проекта автоматически вычислять теги на основании других полей вакансии.

Согласитесь, отличные проекты? Тянет на отдельное веб-приложение или полноценную новую фичу уже существующего приложения. Кстати, если бы у вас была возможность предложить какую-то тему или идею для проекта в Школе программистов, то что бы это могло быть?

А пока вы думаете, пара слов о том, какие технологии были использованы в проектах, и какими получились итоги работы команд над проектами:

Сервис опроса компетенций тимлида


Это полноценное веб-приложение, которое работает независимо от нашего основного hh.ru.

На фронтенде использовались:

  • react
  • react final form
  • redux
  • material-ui-kit для ускорения прототипирования интерфейса

На бекенде:


Все части приложения завернуты в Docker.

Команда проекта выделила следующие пункты как итоги своей работы: разработчики создали сервис с нуля, реализовав основу для дальнейшего развития корпоративной системы оценки навыков. Набрались опыта в работе по agile-методологиям и код-ревью. Создали сплоченную команду и хорошо повеселились.

Сервис рейтинга разработчиков


Это веб-сервис, который работает независимо от нашего основного приложения и полагается только на доступ к аккаунту GitHub.

На фронтенде использовались:

  • react
  • redux
  • final-form
  • date-fns
  • less как препроцессор для стилей

На бекенде:

  • nuts-and-bolts (NaB)
  • jersey
  • hibernate
  • PostgreSQL

Все приложение было поделено на несколько частей: крон, который обновляет статистику с GitHub, бекэнд для подсчета и анализа статистики, фронтенд для отображения графиков, информации и самого рейтинга.

По итогу работы команда представила MVP своего проекта, предложила несколько вариантов развития функциональности.

Сервис по формированию коммерческих предложений для работодателей


Это приложение реализовывалось как отдельный сервис внутри нашей экосистемы микросервисов, относящихся к hh.ru

На фронтенде использовались:

  • react
  • react final form
  • redux
  • material-ui-kit для ускорения прототипирования интерфейса

На бекенде:

  • nuts-and-bolts (NaB)
  • jersey
  • hibernate
  • kafka как технология для передачи событий от систем бизнес-аналитики и веб-приложения к новому сервису
  • PostgreSQL

Одним из основных вызовов для этой команды стала необходимость также поднять у себя копию базы MSSQL Server, так как именно там хранятся данные бизнес-процессов, аналитики и клиентов. Отдельную анонимизированную копию с данными использовали в дальнейшем для демонстрации и тестирования.

Сервис для улучшения качества поисковой выдачи


На фронтенде использовались:

  • react
  • redux
  • less, как препроцессор для стилей

На бекенде:

  • nuts-and-bolts (NaB)
  • jersey
  • hibernate
  • PostgreSQL

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

Лучшей же оценкой самого проекта стало пожелание продакт-менеджера поиска поскорей выкатывать сервис в продакшен.

Сервис для тегирования вакансий


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

На фронтенде для реализации админки использовались:

  • react
  • redux
  • less

На бекенде для сбора и анализа данных:

  • nuts-and-bolts (NaB)
  • jersey
  • hibernate
  • PostgreSQL
  • Apache Lucene
  • Яндекс.Танк для нагрузочного тестирования

Основным челленджем стало погружение в ML, изучение метрик TF-IDF, PMI и их производных. На финальном демо команда поделилась тем, что основными трудностями при реализации алгоритма стали: отсутствие достаточного времени для анализа данных, отсутствие метрик качества, чтобы сравнивать алгоритмы и очень большая вариативность в параметрах модели.

Мы уверены, что идеи и их реализации получились достойными нашей юбилейной Школы. А 22 выпускника станут отличными программистами да чего скромничать, они уже стали. 11 из них мы позвали работать к нам, а остальным предоставим рекомендации и приложили усилия, чтобы ребята попали в хорошую компанию!

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

Кстати, набор в одиннадцатую Школу Программистов в самом разгаре. Более того, в этом году мы полностью переходим в онлайн, и в связи с этим мы увеличили количество мест до 40, а заявки теперь можно подавать из любого города нашей необъятной! Если этот опыт окажется успешным, то мы приложим все усилия, чтобы Школа осталась online навсегда.

Обучение полностью бесплатное.

Алгоритм поступления проще, чем сортировка пузырьком:

1. заполни анкету на сайте

2. выполни тестовое задание

3. пройди online-собеседование с нашими сотрудниками

Мы ждем тебя в нашей Школе!


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

Новое CSS-свойство content-visibility ускоряет отрисовку страницы в несколько раз

13.08.2020 10:12:29 | Автор: admin
5 августа 2020 разработчики Google анонсировали новое CSS-свойство content-visibility в версии Chromium 85. Оно должно существенно повлиять на скорость первой загрузки и первой отрисовки на сайте; причём с только что отрендеренным контентом можно взаимодействовать сразу же, не дожидаясь загрузки остального содержимого. content-visibility заставляет юзер-агент пропускать разметку и покраску элементов, не находящихся на экране. По сути, это работает как lazy-load, только не на загрузке ресурсов, а на их отрисовке.


В этой демке content-visibility: auto, применённый к разбитому на части контенту, даёт прирост скорости рендера в 7 раз


Поддержка


content-visibility основывается на примитивах из спецификации CSS Containment. Хотя на данный момент content-visibility поддерживается только в Chromium 85 (и считается достойным прототипирования в Firefox), спецификация Containment поддерживается в большинстве современных браузеров.

Принцип работы


Основная цель CSS Containment повысить производительность рендеринга веб-контента, обеспечивая предсказуемую изоляцию поддерева DOM от остальной части страницы.

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

Всего есть четыре типа CSS Containment, каждое выступает значением для CSS-свойства contain и может быть скомбинировано с другими:

  • size: Ограничение размера элемента гарантирует, что блок элемента может быть размещен без необходимости изучения его потомков. То есть, зная размер элемента, мы вполне можем опустить вычисление расположения его потомков.
  • layout: Ограничение выкладки не даёт потомкам повлиять на внешнее расположение других блоков на странице. Это позволяет нам потенциально опустить размещение потомков, если все, что мы хотим сделать, это расположить другие блоки.
  • style: Ограничение стилей гарантирует, что свойства, влияющие не только на его потомков, не покидают элемент (например, счетчики). Это позволяет пропустить вычисление стилей для потомков, если все, что нам нужно, это вычислить стили для других элементов.
  • paint: Ограничение покраски не позволяет потомкам отображаться за пределами своего контейнера. Ничего не будет налезать на элемент, и если он находится за границами экрана или так или иначе невидим, его потомки также будут невидимы. Это позволяет не отрисовывать потомков, если элемент уже за краями экрана.


Пропускаем рендеринг с content-visibility



Может быть непонятно, какие значения contain лучше использовать, поскольку оптимизация браузера может сработать только при правильно указанном наборе параметров. Стоит поиграться со значениями, чтобы эмпирическим путём узнать, что работает лучше всего. А лучше использовать content-visibility для автоматической настройки contain. content-visibility: auto гарантирует максимальный возможный прирост производительности при минимальных усилиях.

В автоматическом режиме свойство получает атрибуты layout, style и paint, а при выходе элемента за края экрана, получает size и перестаёт красить и проверять содержимое. Это значит, что как только элемент выходит из зоны отрисовки, его потомки перестают рендериться. Браузер распознает размеры элемента, но больше не делает ничего, пока в отрисовке не возникнет необходимость.

Пример тревел-блог


Your browser does not support HTML5 video.


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

  • Часть страницы загружается из сети вместе с необходимыми ресурсами
  • Браузер стилизует и размещает весь контент на странице, не различая контент на видимый и невидимый
  • Браузер переходит к шагу 1 до того пока не загрузит все ресурсы

На шаге 2 браузер обрабатывает содержимое, пытаясь найти изменения. Он обновляет стили и расположение любого нового элемента вместе с элементами которые могли быть изменены в результате обновлений. Это рендеринг. Он занимает время.



Теперь представим, что мы поместили content-visibility: auto на каждый пост в блоге. Основная система та же: браузер загружает и рендерит части страницы. Однако, разница в количестве работы, сделанной в шаге 2. С content-visibility браузер будет стилизовать и размещать тот контент который сейчас видит пользователь (на экране). Но обрабатывая истории вне экрана, браузер будет пропускать рендеринг всего элемента и будет размещать только контейнер. Производительность загрузки этой страницы будет как если бы она содержала заполненные посты на экране и пустые контейнеры для каждого поста вне его. Так получается гораздо быстрее, выигрыш составляет до 50% от времени загрузки. В нашем примере мы видим улучшение с 232мс рендеринга до 30мс, это улучшение производительности в 7 раз.

Что нужно сделать чтобы воспользоваться этими преимуществами? Во-первых, мы разделяем контент на части:



После, мы применяем последующую стилизацию на части:

    .story {        content-visibility: auto;        contain-intrinsic-size: 1000px; /* Объяснено далее */    }


Обратите внимание, что когда контент перемещается с экрана, он будет рендериться по необходимости. Однако, это не означает что браузер должен будет рендерить один и тот же контент раз за разом, ведь работа рендеринга сохраняется, когда это возможно.


Определение типичного размера элемента с contain-intrinsic-size


Для того чтобы понять потенциальные преимущества content-visibility, браузер должен применять ограничения по размеру, чтобы гарантировать, что результаты рендеринга контента не будут влиять на размеры элементов. Это означает что элемент будет размещен как если бы он был пустой. Если у элемента не определена высота, то она будет равна нулю.

К счастью, у css есть ещё одна способность, contain-intrinsic-sizе, которая предоставляет возможность определить настоящий размер элемента, если тот подвергся сжатию. В нашем примере мы устанавливаем ширину и высоту примерно 1000px.
Это означает, что он будет располагаться так, будто там один файл внутренного размера, при этом гарантируя, что div все ещё занимает место. contain-intrinsic-sizе выступает в качестве заполнителя.

Скрываем контент с content-visibility: hidden


content-visibility: hidden делает то же, что и content-visibility: auto делает с контентом вне экрана. Однако, в отличие от auto, он не начинает автоматический рендеринг контента на экране.

Сравним его с обычными способами спрятать контент элемента:

  • display: none: скрывает элемент и удаляет состояние рендеринга. Это означает что доставая элемент будет стоить той же нагрузки как и создание нового элемента.
  • visibility: hidden: скрывает элемент и оставляет состояние рендеринга. Это на самом деле не удаляет элемент из документа, так как он (и его поддерево) все еще занимает геометрическое пространство на странице и по-прежнему может быть нажат. Он также обновляет состояние рендеринга в любое время, когда это необходимо, даже если он скрыт.

content-visibility: hidden, с другой стороны, скрывает элемент, сохраняя состояние рендеринга, так что если будут необходимы какие-либо изменения, они произойдут только при показе элемента на экране.

Заключение


content-visibility и CSS Containment Spec позволяют значительно ускорять рендеринг и загрузку страниц без каких-либо сложных манипуляций, на голом CSS.
The CSS Containment Spec
MDN Docs on CSS Containment
CSSWG Drafts



На правах рекламы


Серверы для размещения сайтов это про наши эпичные! Все серверы из коробки защищены от DDoS-атак, автоматическая установка удобной панели управления VestaCP. Лучше один раз попробовать ;)

Подробнее..

Категории

Последние комментарии

© 2006-2020, personeltest.ru