<?xml version="1.0" encoding="utf-8" ?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:tt="http://teletype.in/" xmlns:opensearch="http://a9.com/-/spec/opensearch/1.1/"><title>Александр Архипов</title><subtitle>Пытаюсь общаться с компухтерами на их языках.</subtitle><author><name>Александр Архипов</name></author><id>https://teletype.in/atom/helvetios</id><link rel="self" type="application/atom+xml" href="https://teletype.in/atom/helvetios?offset=0"></link><link rel="alternate" type="text/html" href="https://teletype.in/@helvetios?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=helvetios"></link><link rel="next" type="application/rss+xml" href="https://teletype.in/atom/helvetios?offset=10"></link><link rel="search" type="application/opensearchdescription+xml" title="Teletype" href="https://teletype.in/opensearch.xml"></link><updated>2026-04-16T10:19:53.141Z</updated><entry><id>helvetios:parcel-pug-pictures</id><link rel="alternate" type="text/html" href="https://teletype.in/@helvetios/parcel-pug-pictures?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=helvetios"></link><title>Parcel &amp; Pug – особенности работы с изображениями </title><published>2023-05-30T03:18:54.726Z</published><updated>2023-05-30T03:18:54.726Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img1.teletype.in/files/02/14/02140dc7-9edf-4309-afe9-817ea0873114.png"></media:thumbnail><category term="webdev" label="Веб-разработка"></category><summary type="html">&lt;img src=&quot;https://img1.teletype.in/files/45/f6/45f6314c-7596-4322-9ff6-007b34bc4d32.png&quot;&gt;Привет. Когда в обучении фронту я дошел до картиночек и вставки их на страницу я был слегка удивлён. Когда дошел до их адаптивности уже был не слегка.</summary><content type="html">
  &lt;figure id=&quot;IagD&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/45/f6/45f6314c-7596-4322-9ff6-007b34bc4d32.png&quot; width=&quot;1200&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;K36f&quot;&gt;Привет. Когда в обучении фронту я дошел до картиночек и вставки их на страницу я был слегка удивлён. Когда дошел до их адаптивности уже был не слегка.&lt;/p&gt;
  &lt;p id=&quot;8uni&quot;&gt;Казалось бы, тег &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; ему атрибутом &lt;code&gt;src=&amp;#x27;котик.png&amp;#x27;&lt;/code&gt; да и всё, ан нет. Естественно, нужен как минимум &lt;code&gt;alt&lt;/code&gt;, а то валидацию не пройдет и дядя SEO-шник даст пизды, потом еще обязательно &lt;code&gt;width&lt;/code&gt; / &lt;code&gt;height&lt;/code&gt;, а то контент-манагер еще вставит 10мегапикселов фото и всё поедет как твоя кукуха.&lt;/p&gt;
  &lt;p id=&quot;PYIx&quot;&gt;И это только статика, через CSS &amp;quot;адаптивно&amp;quot; ты можешь только тянуть картинку передавая привет всем шакалам, койотам и всем остальным безумно можно быть первым. Можно все пофиксить &lt;code&gt;object-fit&lt;/code&gt;, но тогда либо у тебя махонькая картинка на десктопе, либо FullHD на телефоне, что само по себе слегка похоже на выбор стула из... нутыпоэл.&lt;/p&gt;
  &lt;p id=&quot;Wxfc&quot;&gt;Ах, да! Еще же эти ваши ретина-дисплеи и, конечно же, новые модные-молодёжные &lt;s&gt;реп-дискета-дискотека&lt;/s&gt; лёгкие форматы WebP и AVIF.&lt;/p&gt;
  &lt;p id=&quot;X3sw&quot;&gt;Итого у нас получается, что одна картинка - это не одна картинка, а в очень минимум варианте две-три, а по хорошему... хм... Восемнадцать! И все их надо верно разметить в &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt;.&lt;/p&gt;
  &lt;p id=&quot;iLz2&quot;&gt;Готовить всё это ручками, конечно, дело не боярское.&lt;/p&gt;
  &lt;h2 id=&quot;qEQn&quot;&gt;Автоматизируй&lt;/h2&gt;
  &lt;p id=&quot;RgBH&quot;&gt;Естественно, мыжпрограммисты. На это есть всякие бандлеры, например - Gulp, Webpack или сегодняшний пациент - &lt;a href=&quot;https://parceljs.org/&quot; target=&quot;_blank&quot;&gt;Parcel&lt;/a&gt;. Их вообще дофига, но самые популярные для фронта, насколько я понимаю, эти трое.&lt;/p&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;dhvj&quot;&gt;На самом деле все они, так или иначе, работают через один и тот же инструмент – плагин или модуль Node.js (я еще не до конца просёк терминологию) под названием &lt;a href=&quot;https://sharp.pixelplumbing.com/&quot; target=&quot;_blank&quot;&gt;Sharp&lt;/a&gt;. Работает просто - даёшь ему картинку, говоришь чего с ней сделать, отдаёт тебе картинку.&lt;/p&gt;
  &lt;/section&gt;
  &lt;p id=&quot;P2lX&quot;&gt;Parcel сам по себе мощная штука, хотя и специфическая, но об этом в другой раз. Самое главное - он умеет из коробки &lt;a href=&quot;https://parceljs.org/recipes/image/&quot; target=&quot;_blank&quot;&gt;работать с Sharp&lt;/a&gt;, а как следствие с картинками и более того, позволяет без всяких конфигов прямо в HTML и CSS указать что с картинкой делать. &lt;/p&gt;
  &lt;p id=&quot;DV6J&quot;&gt;Пример из документации:&lt;/p&gt;
  &lt;pre id=&quot;nDtU&quot; data-lang=&quot;html&quot;&gt;&amp;lt;picture&amp;gt;
  &amp;lt;source srcset=&amp;quot;image.jpeg?as=avif&amp;amp;width=800&amp;quot; type=&amp;quot;image/avif&amp;quot; /&amp;gt;
  &amp;lt;source srcset=&amp;quot;image.jpeg?as=webp&amp;amp;width=800&amp;quot; type=&amp;quot;image/webp&amp;quot; /&amp;gt;
  &amp;lt;source srcset=&amp;quot;image.jpeg?width=800&amp;quot; type=&amp;quot;image/jpeg&amp;quot; /&amp;gt;
  &amp;lt;img src=&amp;quot;image.jpeg?width=200&amp;quot; alt=&amp;quot;test image&amp;quot; /&amp;gt;
&amp;lt;/picture&amp;gt;&lt;/pre&gt;
  &lt;p id=&quot;p3wG&quot;&gt;Задача для Sharp формируется с помощью query-параметра после знака &lt;code&gt;?&lt;/code&gt; в пути к картинке. Если параметра, читай задачи, два - их соединяем символом &lt;code&gt;&amp;amp;&lt;/code&gt;. В нашем случае у первого &lt;code&gt;&amp;lt;source&amp;gt;&lt;/code&gt; мы &amp;quot;попросили&amp;quot; Parcel сконвертировать &lt;code&gt;image.jpeg&lt;/code&gt; в формат AVIF - &lt;code&gt;as=avif&lt;/code&gt;, и изменить размер на 800px по ширине - &lt;code&gt;width=800&lt;/code&gt;. По умолчанию, высота ресайзится пропорционально.&lt;/p&gt;
  &lt;p id=&quot;dJvs&quot;&gt;Кроме конвертации &lt;code&gt;as=&lt;/code&gt; и размеров &lt;code&gt;width=&lt;/code&gt;/&lt;code&gt;height=&lt;/code&gt;, можно еще задать уровень качества, то бишь степень сжатия через &lt;code&gt;quality=&lt;/code&gt;, но я никогда не трогал её, так как дефолтные &lt;code&gt;75&lt;/code&gt; меня устраивают.&lt;/p&gt;
  &lt;p id=&quot;0gQW&quot;&gt;То есть, по сути нам нужна только одна jpeg/png картинка-исходник, самая большая - всё остальное можно сделать через Parcel и прям в разметке указать чего куда подставить. Примерный пример - картинка-исходник 960px в ширину для ретина 2х, остальное делаем через параметры:&lt;/p&gt;
  &lt;pre id=&quot;hQnM&quot; data-lang=&quot;html&quot;&gt;&amp;lt;picture&amp;gt;
  &amp;lt;!-- desktop: avif, webp, png с ретиной --&amp;gt;
  &amp;lt;source 
    type=&amp;quot;image/avif&amp;quot; media=&amp;quot;(min-width: 1280px)&amp;quot; 
    srcset=&amp;quot;pic.png?as=avif&amp;amp;width=480, pic.png?as=avif 2x&amp;quot; /&amp;gt;
  &amp;lt;source 
    type=&amp;quot;image/webp&amp;quot; media=&amp;quot;(min-width: 1280px)&amp;quot; 
    srcset=&amp;quot;pic.png?as=webp&amp;amp;width=480, pic.png?as=webp 2x&amp;quot; /&amp;gt;
  &amp;lt;source 
    type=&amp;quot;image/png&amp;quot; media=&amp;quot;(min-width: 1280px)&amp;quot; 
    srcset=&amp;quot;pic.png?width=480, pic.png 2x&amp;quot; /&amp;gt;
    
  &amp;lt;!-- tablet, ресайз условный --&amp;gt;
  &amp;lt;source 
    type=&amp;quot;image/avif&amp;quot; media=&amp;quot;(min-width: 768px)&amp;quot; 
    srcset=&amp;quot;pic.png?as=avif&amp;amp;width=320, pic.png?as=avif&amp;amp;width=640 2x&amp;quot; /&amp;gt;
  &amp;lt;source 
    type=&amp;quot;image/webp&amp;quot; media=&amp;quot;(min-width: 768px)&amp;quot; 
    srcset=&amp;quot;pic.png?as=webp&amp;amp;width=320, pic.png?as=webp&amp;amp;width=640 2x&amp;quot; /&amp;gt;
  &amp;lt;source 
    type=&amp;quot;image/png&amp;quot; media=&amp;quot;(min-width: 768px)&amp;quot; 
    srcset=&amp;quot;pic.png?width=320, pic.png?width=640 2x&amp;quot; /&amp;gt;
    
  &amp;lt;!-- mobile --&amp;gt;
  &amp;lt;source 
    type=&amp;quot;image/avif&amp;quot; 
    srcset=&amp;quot;pic.png?as=avif&amp;amp;width=260, pic.png?as=avif&amp;amp;width=520 2x&amp;quot; /&amp;gt;
  &amp;lt;source 
    type=&amp;quot;image/webp&amp;quot;
    srcset=&amp;quot;pic.png?as=webp&amp;amp;width=260, pic.png?as=webp&amp;amp;width=520 2x&amp;quot; /&amp;gt;
  &amp;lt;img
    alt=&amp;quot;picture&amp;quot; width=&amp;quot;260&amp;quot; height=&amp;quot;180&amp;quot;
    src=&amp;quot;pic.png?width=260&amp;quot; srcset=&amp;quot;pic.png?width=520 2x&amp;quot; /&amp;gt;
&amp;lt;/picture&amp;gt;&lt;/pre&gt;
  &lt;p id=&quot;EAeu&quot;&gt;В CSS, кстати, тоже работает, но функцию &lt;code&gt;image-set()&lt;/code&gt; пока &lt;a href=&quot;https://caniuse.com/css-image-set&quot; target=&quot;_blank&quot;&gt;хреновенько&lt;/a&gt; поддерживают браузеры.&lt;/p&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;eO3d&quot;&gt;В прошлой статье я частично использовал этот инструмент, но не до конца разобрался, плюс нюансы есть с Pug&amp;#x27;ом, о чем дальше.&lt;/p&gt;
  &lt;/section&gt;
  &lt;p id=&quot;bhBX&quot;&gt;Штош. Миллион картинок нам теперь не нужны, но верстать всё еще надо весь десяток тегов для каждой контентной картинки. А что если это карточки в  каталоге или галерея? Прокачивай десятипалый набор или...&lt;/p&gt;
  &lt;h2 id=&quot;8duB&quot;&gt;Шаблонизируй&lt;/h2&gt;
  &lt;p id=&quot;ogCf&quot;&gt;Наверное, надо было наоборот, но на примере простого HTML проще понять как происходит конвертация в Parcel/Sharp.&lt;/p&gt;
  &lt;p id=&quot;Drf5&quot;&gt;Я использую &lt;a href=&quot;https://pugjs.org/&quot; target=&quot;_blank&quot;&gt;Pug.js&lt;/a&gt; так как просто захотел выучить новенькое и он попался первым. О самом Pug&amp;#x27;е я в &lt;a href=&quot;https://blog.arkhelvetios.ru/pugjs-hi&quot; target=&quot;_blank&quot;&gt;прошлой статье&lt;/a&gt; писал, для текущей задачи можно много чего придумать - я решил воспользоваться &lt;code&gt;mixin&lt;/code&gt;&amp;#x27;ом.&lt;/p&gt;
  &lt;p id=&quot;Zlph&quot;&gt;Мы создаём шаблон какого-то куска разметки и передавая в него параметры расставляем их в теле шаблона:&lt;/p&gt;
  &lt;pre id=&quot;aT5H&quot; data-lang=&quot;pug&quot;&gt;mixin item(name, path, desc) 
  li 
    h3 name
    img(src=path, alt=name) 
    p desc

+item(&amp;#x27;Mr. Puggy&amp;#x27;, &amp;#x27;./mr-puggy.png&amp;#x27;, &amp;#x27;Distinguished gentleman&amp;#x27;)&lt;/pre&gt;
  &lt;p id=&quot;AZkH&quot;&gt;Сами вызовы миксинов, читай создание элемента по шаблону, можно воткнуть, например, в местный цикл, а данные передавать из объекта:&lt;/p&gt;
  &lt;pre id=&quot;Mnwu&quot; data-lang=&quot;pug&quot;&gt;each item in gallery-items
  +item(item.name, item.path, item.desc)&lt;/pre&gt;
  &lt;p id=&quot;jL9L&quot;&gt;Объект, кстати, можно подключить внешний, правда, немного через жопу, то есть через конфиг-файл Pug&amp;#x27;а. У конфига &lt;code&gt;.pugrc&lt;/code&gt; есть зарезервированный объект &lt;code&gt;locals&lt;/code&gt; в который можно пихать свои данные, а в &lt;code&gt;.pug&lt;/code&gt; файлах обращаться к самому вложенному объекту, так как &lt;code&gt;locals&lt;/code&gt; работает для всей страницы.&lt;/p&gt;
  &lt;pre id=&quot;ZbjQ&quot; data-lang=&quot;javascript&quot;&gt;// пример .pugrc (или pug.config.js)
{
  &amp;quot;locals&amp;quot;: {
    &amp;quot;gallery-items&amp;quot;: [
      {
        &amp;quot;name&amp;quot;: &amp;quot;Mr. Puggy&amp;quot;,
        &amp;quot;path&amp;quot;: &amp;quot;./mr-puggy.png&amp;quot;,
        &amp;quot;desc&amp;quot;: &amp;quot;Distinguished gentleman&amp;quot;
      },
      {
        &amp;quot;name&amp;quot;: &amp;quot;Don Fluffy&amp;quot;,
        &amp;quot;path&amp;quot;: &amp;quot;./don-fluffy.png&amp;quot;,
        &amp;quot;desc&amp;quot;: &amp;quot;Mafioso&amp;quot;
      }
    ]
  }
}&lt;/pre&gt;
  &lt;h2 id=&quot;JlBu&quot;&gt;Ах, да! Особенности!&lt;/h2&gt;
  &lt;p id=&quot;RPNC&quot;&gt;Остались нюансы. С первым я столкнулся в прошлый раз - Pug&amp;#x27;овская &lt;a href=&quot;https://pugjs.org/language/attributes.html#attribute-interpolation&quot; target=&quot;_blank&quot;&gt;интерполяция&lt;/a&gt;, которая &lt;code&gt;#{foo}&lt;/code&gt;, действительно не работает в атрибутах, о чем сказано в документации. Там же в документации, написаны варианты выхода из ситуации – конкатенация прям в атрибуте или использовать ES-ную интерполяцию с бэктиками - &lt;code&gt;&amp;#x60;${foo}&amp;#x60;&lt;/code&gt;.&lt;/p&gt;
  &lt;p id=&quot;6RJQ&quot;&gt;Я выбрал второй вариант и пока не пожалел - получилось лаконичнее и, на мой взгляд, даже читабельнее чем с ворохом конкатенаций.&lt;/p&gt;
  &lt;pre id=&quot;FhDl&quot; data-lang=&quot;javascript&quot;&gt;mixin item(name, path, desc)
  //- контент шаблона
  ...
  picture
    source( 
      srcset=&amp;#x60;${path}?as=avif&amp;amp;width=480, ${path}?as=avif 2x&amp;#x60;, 
      media=&amp;#x27;(min-width: 1280px)&amp;#x27;, 
      type=&amp;#x27;image/avif&amp;#x27;
      )
    ...
    // остальные sources аналогично&lt;/pre&gt;
  &lt;p id=&quot;zci0&quot;&gt;Второй нюанс это &lt;a href=&quot;https://pugjs.org/language/attributes.html#unescaped-attributes&quot; target=&quot;_blank&quot;&gt;экранирование специальных символов&lt;/a&gt; в атрибутах. В Pug символы типа &lt;code&gt;&amp;lt;&lt;/code&gt;, &lt;code&gt;&amp;gt;&lt;/code&gt; и нужный нам амперсанд &lt;code&gt;&amp;amp;&lt;/code&gt; по умолчанию экранируются и преобразуются в мнемоники типа &lt;code&gt;&amp;amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;amp;lt;&lt;/code&gt; и так далее.&lt;/p&gt;
  &lt;p id=&quot;BFSV&quot;&gt;Чтобы символы не экранировались достаточно просто поставить &lt;code&gt;!&lt;/code&gt; перед равно при написании атрибута:&lt;/p&gt;
  &lt;pre id=&quot;ByDV&quot; data-lang=&quot;javascript&quot;&gt;source(
  srcset!=&amp;#x60;${path}?as=avif&amp;amp;width=480, ${path}?as=avif 2x&amp;#x60;, 
  ...
)&lt;/pre&gt;
  &lt;p id=&quot;6ooB&quot;&gt; Да, даже подсветка говорит нам, мол это же &amp;quot;НЕравно&amp;quot;, но такой вот синтаксис.&lt;/p&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;yAO4&quot;&gt;По итогу, пару дней покопавшись оказалось, что не так уж всё и страшно с этими картиночками. Вот боевой пример с одной странице, где плитка с портфолио:&lt;/p&gt;
  &lt;figure id=&quot;HUYO&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/f2/6f/f26f752c-2ef1-4e41-bc42-882509c6a3ad.png&quot; width=&quot;973&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;LHFm&quot;&gt;Массив &lt;code&gt;portfolio&lt;/code&gt; я вынес в &lt;code&gt;locals&lt;/code&gt;, получается там такая база данных на минималках. В конкретном примере 12 картинок, так как нет необходимости делать под таблет - по дизайну они просто смещаются сверху вбок от текста.&lt;/p&gt;
  &lt;p id=&quot;JBV3&quot;&gt;Всё, спасибо за внимание!&lt;/p&gt;

</content></entry><entry><id>helvetios:pugjs-hi</id><link rel="alternate" type="text/html" href="https://teletype.in/@helvetios/pugjs-hi?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=helvetios"></link><title>Pug.js – мое знакомство с мопсовым препроцессором</title><published>2023-05-18T19:08:25.937Z</published><updated>2023-05-19T13:17:23.954Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img4.teletype.in/files/39/af/39af021d-a19d-43ea-afe4-c6a8292215c8.png"></media:thumbnail><category term="webdev" label="Веб-разработка"></category><summary type="html">&lt;img src=&quot;https://img2.teletype.in/files/9b/81/9b81320c-c7bc-4787-9617-557f5fe5742a.png&quot;&gt;Привет. Недавно решил собрать себе архив из своих работ по вёб-дезигну, которые делал последние несколько лет, до фронт-энда. Оказалось их немало, большая часть из них, к сожалению, утрачены, но даже так получился список из двадцати с чем-то работ. А раз уж я теперь фронт-энд разработчик, то запилю это всё дело в виде странички.</summary><content type="html">
  &lt;figure id=&quot;n88W&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/9b/81/9b81320c-c7bc-4787-9617-557f5fe5742a.png&quot; width=&quot;1200&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;GdJ5&quot;&gt;Привет. Недавно решил собрать себе архив из своих работ по вёб-дезигну, которые делал последние несколько лет, до фронт-энда. Оказалось их немало, большая часть из них, к сожалению, утрачены, но даже так получился список из двадцати с чем-то работ. А раз уж я теперь фронт-энд разработчик, то запилю это всё дело в виде странички.&lt;/p&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;9bvE&quot;&gt;Так как это, своего рода, пет-проект, параллельно захотелось освоить что-то новенькое и как-то сам по себе выбрался препроцессор для вёрстки Pug. Если честно, я из-за названия и выбрал. 😃&lt;/p&gt;
  &lt;p id=&quot;ALUc&quot;&gt;У Pug&amp;#x27;а интересный python&amp;#x27;оподбоный синтаксис, основанный на индентах, то бишь вложенность элементов определяется не закрывающими тегами, а отступом:&lt;/p&gt;
  &lt;pre id=&quot;RxBf&quot; data-lang=&quot;pug&quot;&gt;ul.list
  li.list__item Item A
    ul.list__sublist
      li.list__subitem#unique-id Subitem A1
      li.list__subitem Subitem A2
  li.list__item Item B
  li.list__item Item C&lt;/pre&gt;
  &lt;p id=&quot;Eyos&quot;&gt;На выходе получится:&lt;/p&gt;
  &lt;pre id=&quot;5tNY&quot; data-lang=&quot;html&quot;&gt;&amp;lt;ul class=&amp;quot;list&amp;quot;&amp;gt;
  &amp;lt;li class=&amp;quot;list__item&amp;quot;&amp;gt;Item A
    &amp;lt;ul class=&amp;quot;list__sublist&amp;quot;&amp;gt;
      &amp;lt;li class=&amp;quot;list__subitem&amp;quot; id=&amp;quot;unique-id&amp;quot;&amp;gt;Subitem A1&amp;lt;/li&amp;gt;
      &amp;lt;li class=&amp;quot;list__subitem&amp;quot;&amp;gt;Subitem A2&amp;lt;/li&amp;gt;
    &amp;lt;/ul&amp;gt;
  &amp;lt;/li&amp;gt;
  &amp;lt;li class=&amp;quot;list__item&amp;quot;&amp;gt;li Item B&amp;lt;/li&amp;gt;
  &amp;lt;li class=&amp;quot;list__item&amp;quot;&amp;gt;li Item C&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;  &lt;/pre&gt;
  &lt;p id=&quot;7WYR&quot;&gt;Класс можно задать через точку, ID через диез, прям как селектор в CSS, правда на ID-шник через диез ругается линтер:&lt;/p&gt;
  &lt;figure id=&quot;eZq8&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/7a/a0/7aa01b1c-a899-4c4f-95bd-b45d0154ad7c.png&quot; width=&quot;502&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;aRBL&quot;&gt;Лучше его задавать как обычные атрибуты, которые задаются в скобках через запятую, как своеобразные аргументы функции:&lt;/p&gt;
  &lt;pre id=&quot;CusZ&quot; data-lang=&quot;pug&quot;&gt;img(src=&amp;#x27;./pic.png&amp;#x27;, alt=&amp;#x27;super pic&amp;#x27;, width=&amp;#x27;100&amp;#x27;, height=&amp;#x27;50&amp;#x27;)&lt;/pre&gt;
  &lt;p id=&quot;gn5R&quot;&gt;Но одним относительно упрощенным синтаксисом, конечно, Pug не ограничивается. Так как это препроцессор, в нём возможны все &amp;quot;программистские&amp;quot; штучки - условия, циклы, интерполяция и функции. Можно еще прямо в .pug файле писать JavaScript, ограничено, но можно.&lt;/p&gt;
  &lt;p id=&quot;lDSK&quot;&gt;Правда, ни условиями ни циклами я так и не воспользовался, но воспользовался тремя инструментами, которые значительно сэкономили мне время.&lt;/p&gt;
  &lt;h2 id=&quot;xnCr&quot;&gt;Mixins&lt;/h2&gt;
  &lt;p id=&quot;muWJ&quot;&gt;Это такая функция-конструктор, мы задаём ей параметры в аргументах, внутри задаём шаблон и эти параметры расставляем где надо, затем вызываем:&lt;/p&gt;
  &lt;pre id=&quot;OU2w&quot; data-lang=&quot;pug&quot;&gt;mixin item(foo, baz, bar)
  li
    h3 foo
    img(src=baz, alt=foo)
    p bar
    
+item(&amp;#x27;Mr. Puggy&amp;#x27;, &amp;#x27;./mr-puggy.png&amp;#x27;, &amp;#x27;Distinguished gentleman&amp;#x27;)&lt;/pre&gt;
  &lt;p id=&quot;f7MA&quot;&gt;Я использовал его для карточек в списке своих работ:&lt;/p&gt;
  &lt;figure id=&quot;TwMA&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/99/79/997979f6-4af8-420b-8cba-c254378c000b.png&quot; width=&quot;817&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;spIe&quot;&gt;У меня тут наворочено с датой и с ссылкой на изображение. Дату я задаю в специальном, &lt;a href=&quot;https://tc39.es/ecma262/multipage/numbers-and-dates.html#sec-date-time-string-format&quot; target=&quot;_blank&quot;&gt;валидном&lt;/a&gt; для атрибута &lt;code&gt;datetime&lt;/code&gt; и JS формате, но для отображения на странице преобразую в строки с годом и месяцем на английском, а потом подставляю интерполяцией в контент.&lt;/p&gt;
  &lt;p id=&quot;V8Y7&quot;&gt;С ссылкой на изображения посложнее так как одно изображение, с целью оптимизации загрузки, существует аж в шести вариантах – jpg и jpg@2x для ретины, webp и webp@2x, и еще avif и avif@2x. Я сделал через конкатенацию строк, так как через интерполяцию в &lt;code&gt;srcset&lt;/code&gt;, вроде как, не получится, по крайней мере линтер на меня ругался и упаковщик послал меня на 404.&lt;/p&gt;
  &lt;h1 id=&quot;IakB&quot;&gt;Includes&lt;/h1&gt;
  &lt;p id=&quot;w5t7&quot;&gt;По своей сути это аналог &lt;code&gt;require()&lt;/code&gt; из PHP - позволяет импортировать кусок внешнего кода в файл. И также позволяет использовать компонентный подход непосредственно в вёрстке.&lt;/p&gt;
  &lt;p id=&quot;7TWw&quot;&gt;Например, у себя я использовал это в хэдере - это блок состоящий из двух блоков - лого и менюшка, которые я подключаю к нему через &lt;code&gt;include&lt;/code&gt;:&lt;/p&gt;
  &lt;figure id=&quot;ODz7&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/72/74/7274695c-9769-467f-9b0e-05a0d5fcae71.png&quot; width=&quot;408&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;4sij&quot;&gt;При этом, все блоки лежат в своих директориях со своими стилями и скриптами:&lt;/p&gt;
  &lt;figure id=&quot;6JBj&quot; class=&quot;m_original&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/e0/63/e0632c89-1feb-4793-b56f-49a926519313.png&quot; width=&quot;267&quot; /&gt;
    &lt;figcaption&gt;Конкретно тут скриптов нет :D&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;7Qwx&quot;&gt;Возможно, это немножечко перебор, но я решил попробовать и никто меня не остановит. Му-ха-хах!&lt;/p&gt;
  &lt;h1 id=&quot;Npct&quot;&gt;Template Inheritance&lt;/h1&gt;
  &lt;p id=&quot;jkfw&quot;&gt;Google переводит как &amp;quot;наследование шаблонов&amp;quot; - к файлу можно подключить структуру внешнего файла. То есть не вставить как кусок разметки через &lt;code&gt;include&lt;/code&gt;, а прям импортировать всё и имея ввиду этот импорт уже работать.&lt;/p&gt;
  &lt;p id=&quot;iLgN&quot;&gt;Такой шаблон должен иметь в себе блоки &lt;code&gt;block&lt;/code&gt; - участки шаблона контент которых можно изменять уже в файле куда подключаем шаблон.&lt;/p&gt;
  &lt;pre id=&quot;DKVF&quot; data-lang=&quot;pug&quot;&gt;html
  head
    title Mr. Puggy Personal Page
    block style
      link(rel=&amp;#x27;stylesheet&amp;#x27;, href=&amp;#x27;./style.css&amp;#x27;)
  body
    ...&lt;/pre&gt;
  &lt;p id=&quot;czHe&quot;&gt;Импортируем шаблон в рабочий файл через команду &lt;code&gt;extends&lt;/code&gt;:&lt;/p&gt;
  &lt;pre id=&quot;MJnJ&quot; data-lang=&quot;pug&quot;&gt;extends template.pug&lt;/pre&gt;
  &lt;p id=&quot;zJHW&quot;&gt;А с блоками можно работать тремя способами – можно перезаписать контент блока просто вызвав его:&lt;/p&gt;
  &lt;pre id=&quot;aH3P&quot; data-lang=&quot;pug&quot;&gt;block style
  link(rel=&amp;#x27;stylesheet&amp;#x27;, href=&amp;#x27;./super-style.css&amp;#x27;)&lt;/pre&gt;
  &lt;p id=&quot;QtKE&quot;&gt;При этом запись из шаблона удалится, то есть стили &lt;code&gt;style.css&lt;/code&gt; не загрузятся. Еще можно добавить записи к шаблону с помощью &lt;code&gt;append&lt;/code&gt; - в конец и &lt;code&gt;prepend&lt;/code&gt; - в начало блока:&lt;/p&gt;
  &lt;pre id=&quot;pZlo&quot; data-lang=&quot;pug&quot;&gt;prepend style
  link(rel=&amp;#x27;stylesheet&amp;#x27;, href=&amp;#x27;./normalize.css&amp;#x27;)
append style
  link(rel=&amp;#x27;stylesheet&amp;#x27;, href=&amp;#x27;./super-style.css&amp;#x27;)&lt;/pre&gt;
  &lt;p id=&quot;YIcX&quot;&gt;Что на выходе, в HTML, даст нам все три тега в нужном нам порядке:&lt;/p&gt;
  &lt;pre id=&quot;yEbD&quot; data-lang=&quot;html&quot;&gt;&amp;lt;head&amp;gt;
  &amp;lt;title&amp;gt;Mr. Puggy Personal Page&amp;lt;/title&amp;gt;
  &amp;lt;link rel=&amp;quot;stylesheet&amp;quot; href=&amp;quot;normalize.css&amp;quot;&amp;gt;
  &amp;lt;link rel=&amp;quot;stylesheet&amp;quot; href=&amp;quot;style.css&amp;quot;&amp;gt;
  &amp;lt;link rel=&amp;quot;stylesheet&amp;quot; href=&amp;quot;super-style.css&amp;quot;&amp;gt;
&amp;lt;/head&amp;gt;&lt;/pre&gt;
  &lt;p id=&quot;lJlR&quot;&gt;Самый простой пример, который я и использовал - я создал шаблон &lt;code&gt;_layout.pug&lt;/code&gt; для типичной страницы, где есть обязательные теги типа &lt;code&gt;doctype&lt;/code&gt;, &lt;code&gt;html&lt;/code&gt;, &lt;code&gt;head&lt;/code&gt; ну и &lt;code&gt;body&lt;/code&gt;. Писать их сто раз на каждой странице дело не боярское, поэтому мы и выводим в шаблон повторяющиеся элементы, а те места которые будут потенциально изменяться оборачиваем в конструкцию &lt;code&gt;block&lt;/code&gt;.&lt;/p&gt;
  &lt;p id=&quot;pWv9&quot;&gt;Например, в &lt;code&gt;head&lt;/code&gt; явно есть мета-информация которая нужна везде:&lt;/p&gt;
  &lt;pre id=&quot;8MUN&quot; data-lang=&quot;pug&quot;&gt;head
  meta(charset=&amp;#x27;utf-8&amp;#x27;) 
  meta(content=&amp;#x27;width=device-width, initial-scale=1&amp;#x27;, name=&amp;#x27;viewport&amp;#x27;) 
  meta(content=&amp;#x27;IE=Edge&amp;#x27;, http-equiv=&amp;#x27;X-UA-Compatible&amp;#x27;)&lt;/pre&gt;
  &lt;p id=&quot;mbgm&quot;&gt;А теги типа &lt;code&gt;title&lt;/code&gt;, какие-то дополнительные стили и скрипты, аля пиксели соц. сетей или метрик, не говоря уже о всяких SEO-тегах - нам нужно подставлять индивидуально для страницы.&lt;/p&gt;
  &lt;p id=&quot;uQCJ&quot;&gt;Грубо говоря, я сделал нечто подобное:&lt;/p&gt;
  &lt;figure id=&quot;tYka&quot; class=&quot;m_original&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/46/2f/462fbad0-2aae-44b3-901e-189c848b5345.png&quot; width=&quot;598&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;xJG9&quot;&gt;Импортирую этот &lt;code&gt;_layout.pug&lt;/code&gt; на страницу, а в &lt;code&gt;head&lt;/code&gt; подставляю всё что нужно через &lt;code&gt;append&lt;/code&gt;. Таким образом, у меня и мета и фавиконки и общие стили уже есть, остаётся добавить несколько строк.&lt;/p&gt;
  &lt;p id=&quot;hmhC&quot;&gt;В &lt;code&gt;body&lt;/code&gt; схема похожая, правда я до конца в ней не уверен:&lt;/p&gt;
  &lt;figure id=&quot;AR6x&quot; class=&quot;m_original&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/aa/ca/aaca43ef-1799-4d78-8de3-91e653f69bb3.png&quot; width=&quot;412&quot; /&gt;
    &lt;figcaption&gt;Нужно еще по хорошему поменять .modal на dialog&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;JqYW&quot;&gt;Тут комбинация блоков и инклудов. Так как блоки можно переписать, можно в любой момент поменять любой блок с условного плейсхолдера на то что нужно.&lt;/p&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;Hylr&quot;&gt;А, собственно все, спасибо за внимание. Как допилю всё - закину сюда ссылочку или может еще чего напишу. Там я еще со сборщиком Parcel&amp;#x27;ем развлекаюсь, есть о чем по бухтеть. &lt;/p&gt;

</content></entry><entry><id>helvetios:gllacy-javascript-slider</id><link rel="alternate" type="text/html" href="https://teletype.in/@helvetios/gllacy-javascript-slider?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=helvetios"></link><title>Бесконечный слайдер на чистом JavaScript — на примере макета Gllacy от HTML Academy</title><published>2022-11-03T14:44:33.623Z</published><updated>2022-11-04T15:38:09.411Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img4.teletype.in/files/78/ff/78ffb175-11e9-4050-a15d-e6917653f023.png"></media:thumbnail><category term="webdev" label="Веб-разработка"></category><summary type="html">&lt;img src=&quot;https://img1.teletype.in/files/08/0a/080a5d26-8083-442e-bdb9-8134d8290159.gif&quot;&gt;Решил я, значит, доделать все проекты из первого уровня HTML Academy и начал с самого, на мой взгляд, сложного — Глейси. Но я был бы не я, если бы не усложнил себе задачу. Я решил, помимо прочего (попапы, тултипы, модалки), реализовать работу слайдера, а он там, мягко говоря, непростой.</summary><content type="html">
  &lt;figure id=&quot;oVYd&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/08/0a/080a5d26-8083-442e-bdb9-8134d8290159.gif&quot; width=&quot;840&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;VzpI&quot;&gt;Решил я, значит, доделать все проекты из первого уровня HTML Academy и начал с самого, на мой взгляд, сложного — Глейси. Но я был бы не я, если бы не усложнил себе задачу. Я решил, помимо прочего (попапы, тултипы, модалки), реализовать работу слайдера, а он там, мягко говоря, непростой.&lt;/p&gt;
  &lt;p id=&quot;6069&quot;&gt;Небольшая повесть о том как я с базовыми знаниями JS решил сделать бесконечный, зацикленный слайдер, с разными позициями элементов, меняющий стиль всего сайта в зависимости от выбранного элемента.&lt;/p&gt;
  &lt;section style=&quot;background-color:hsl(hsl(34,  84%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;hkjN&quot;&gt;&lt;strong&gt;Дисклеймер&lt;/strong&gt;: JS я делал как умею, а на данный момент я никак не умею. &lt;code&gt;:D&lt;/code&gt; Различные продвинутые методы программирования, типа ООП, АОП и т. д., с применением классов, объектных методов и сложных абстракций — это мне еще предстоит изучить. Пока — просто эксперимент.&lt;/p&gt;
    &lt;p id=&quot;q7xf&quot;&gt;&lt;strong&gt;TL;DR&lt;/strong&gt; – &lt;a href=&quot;https://github.com/ArkHelvetios/Gllacy/blob/main/js/slider.js&quot; target=&quot;_blank&quot;&gt;Полный код на GitHub&lt;/a&gt;&lt;/p&gt;
  &lt;/section&gt;
  &lt;p id=&quot;9rVH&quot;&gt;&lt;/p&gt;
  &lt;nav&gt;
    &lt;ul&gt;
      &lt;li class=&quot;m_level_1&quot;&gt;&lt;a href=&quot;#dY9E&quot;&gt;Вёрстка слайдера&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_1&quot;&gt;&lt;a href=&quot;#Oaj3&quot;&gt;Реализация слайдера на JavaScript &lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_2&quot;&gt;&lt;a href=&quot;#TAXm&quot;&gt;Концепт цикличного слайдера&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_2&quot;&gt;&lt;a href=&quot;#aVn4&quot;&gt;Собираем элементы&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_2&quot;&gt;&lt;a href=&quot;#2Ga6&quot;&gt;Клонируем слайды&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_2&quot;&gt;&lt;a href=&quot;#TC0b&quot;&gt;Замена позиции&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_2&quot;&gt;&lt;a href=&quot;#Nc2x&quot;&gt;Плавно переходим&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_1&quot;&gt;&lt;a href=&quot;#rRgo&quot;&gt;Асинхронность JS, переходы и анимация&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_2&quot;&gt;&lt;a href=&quot;#vRCs&quot;&gt;Анимация против inline-переходов&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_2&quot;&gt;&lt;a href=&quot;#ild7&quot;&gt;Собираем всё для анимации&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_2&quot;&gt;&lt;a href=&quot;#dXVH&quot;&gt;Получаем Сomputed значения свойств&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_2&quot;&gt;&lt;a href=&quot;#Dh5P&quot;&gt;Отсеиваем лишние свойства&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_2&quot;&gt;&lt;a href=&quot;#lnEY&quot;&gt;Финальная подстановка&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_1&quot;&gt;&lt;a href=&quot;#sph1&quot;&gt;Остальные задачи&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_2&quot;&gt;&lt;a href=&quot;#kxXz&quot;&gt;Пагинация&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_2&quot;&gt;&lt;a href=&quot;#BuSm&quot;&gt;Смена стилей сайта&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_1&quot;&gt;&lt;a href=&quot;#VlXC&quot;&gt;Ссылки и финал&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/nav&gt;
  &lt;p id=&quot;r1z2&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;dY9E&quot;&gt;Вёрстка слайдера&lt;/h2&gt;
  &lt;p id=&quot;yAZI&quot;&gt;Итак, слайдер это, по сути, весь первый блок. У каждого мороженного свой заголовок, описание и кнопка — это элементы слева. Ещё на макете видно два следующих, неактивных слайда, то бишь превью, у которых тоже есть свой текстовый блок. При этом, превью текстовых, естественно, не видно.&lt;/p&gt;
  &lt;p id=&quot;l9fu&quot;&gt;Если заранее не подумать о последующей реализации, то в плане вёрстки, тут можно по разному подойти, например, сверстать всё одним списком, текст у превью скрывать &lt;code&gt;display: none&lt;/code&gt;, а при слайде показывать. Это первое, что пришло мне в голову.&lt;/p&gt;
  &lt;p id=&quot;8RIE&quot;&gt;И я так даже попробовал, но почти сразу начались огромные проблемы с позиционированием самой картинки, фона-кружочка — пришлось делать обёртку для картинки, отдельно обёртку для текста, проблемы с позиционированием триггеров (они же не должны «слайдиться»). &lt;/p&gt;
  &lt;p id=&quot;BeLD&quot;&gt;До кучи проблема с переполнением — конструкция рушиться если добавить слайд, иначе нужно железно прописывать размер текущего слайда, а из-за этого начинает страдать отображение перехода — ширина скачет от флекс до фикс, некрасиво, а в превью творится вообще кошмар.&lt;/p&gt;
  &lt;figure id=&quot;XlvX&quot; class=&quot;m_column&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/a2/45/a2450424-5f72-4710-909e-4d23e70d6263.png&quot; width=&quot;1185&quot; /&gt;
    &lt;figcaption&gt;Если не фиксировать размер текущего слайда, то flex будет всё сплющивать. &lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;lcW7&quot;&gt;Я же решил сделать красиво и всё это дело анимировать, чтобы это нормально смотрелось, а не «прыгало» мгновениями. Ну и что бы это вообще работало.&lt;/p&gt;
  &lt;p id=&quot;Rdrh&quot;&gt;Моя вторая идея — разделить блок на два структурно независимых блока — текстовый (слева) и с картинками (справа), задать &lt;code&gt;overflow: hidden&lt;/code&gt; контейнерам и поместить внутрь по слайдеру.&lt;/p&gt;
  &lt;figure id=&quot;9pPK&quot; class=&quot;m_column&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/37/b2/37b2f891-c08b-4468-856d-cdf972e0804c.png&quot; width=&quot;1203&quot; /&gt;
    &lt;figcaption&gt;Grid one love&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;Ztvb&quot;&gt;Это слегка увеличило вёрстку, но сильно упростило её логику — слайдеры занимают просто &lt;code&gt;100%&lt;/code&gt; контейнера и живут в своём мирке, прекрасно убирая переполнение за &lt;code&gt;overflow&lt;/code&gt;, а размеры областей заданы в &lt;code&gt;grid&lt;/code&gt;.&lt;/p&gt;
  &lt;p id=&quot;FV0I&quot;&gt;Правда, это слегка нарушило семантику — картинки теперь обособленны от текста, хоть и соотносятся визуально. По идее, наверное, их как-то можно грамотно семантически связать, но я пока не знаю как.&lt;/p&gt;
  &lt;p id=&quot;w7cI&quot;&gt;Еще это потенциально усложнило JS — листать теперь надо два слайда, при том, что в одном у нас есть превью на 2 слайда вперёд, а в другом нет. &lt;/p&gt;
  &lt;p id=&quot;uQDo&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;Oaj3&quot;&gt;Реализация слайдера на JavaScript &lt;/h2&gt;
  &lt;p id=&quot;rZry&quot;&gt;Кроме модалок при обучении на примере Техномарта и Кекстаграма в тренажёрах я, в общем-то, ничего не делал. В тренажёрах по JS разбирался базис языка и небольшой блок про работу с DOM. Короче говоря, это мой первый такой самостоятельный практический вызов.&lt;/p&gt;
  &lt;p id=&quot;hKDp&quot;&gt;Поэтому мне было сложно в принципе понять с чего начать. Самая первая проблема которая бросилась мне в голову — превью у картиночного слайдера. Два проклятых итема торчат справа и намекают, что при слайде влево будет образовываться пустота, а при слайде вправо вообще не понятно чего делать.&lt;/p&gt;
  &lt;p id=&quot;Umft&quot;&gt;Вариант отключить &lt;code&gt;disabled&lt;/code&gt; кнопку «влево» при текущем первом слайде решал только пол беды. В итоге идея реализации зацикленного слайдера напросилась сама — не будем ничего дизеблить, кликать можно в любую сторону.&lt;/p&gt;
  &lt;p id=&quot;xnTT&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;TAXm&quot;&gt;Концепт цикличного слайдера&lt;/h3&gt;
  &lt;p id=&quot;U6Cg&quot;&gt;Итак, как же сделать зацикленный слайдер? Пока без вопроса реализации самого смещения, только концепт «зацикленности». Первое, что пришло в голову мне — это каким-то образом перемещать слайды к краю массива. Смастерить, такой, как бы портал, которые перемещал бы итемы в зависимости от направления к концу или к началу списка.&lt;/p&gt;
  &lt;p id=&quot;wBGJ&quot;&gt;Сразу две проблемы с которыми я столкнулся:&lt;/p&gt;
  &lt;ol id=&quot;lb3m&quot;&gt;
    &lt;li id=&quot;uAFi&quot;&gt;Так как смещение не мгновенное, то одновременно на экране в моменте видно сразу два одинаковых итема — первый, ещё не исчезнувший &lt;code&gt;current&lt;/code&gt; и второй появляющийся с конца.&lt;/li&gt;
    &lt;li id=&quot;8PNs&quot;&gt;Метод &lt;code&gt;.querySelectorAll()&lt;/code&gt; собирает их не в обычный объект (или словарь (?) объектов, тут пока для меня мутная терминология), а в так называемый NodeList, который можно только читать &lt;code&gt;read-only&lt;/code&gt; и нельзя изменять. Об этом я узнал уже в процессе и об этом чуть далее.&lt;/li&gt;
  &lt;/ol&gt;
  &lt;p id=&quot;zoup&quot;&gt;В поисках я находил реализацию такой swap-техники слайдера, но там какие-то либо супер сложные схемы с пересозданием элементов, либо jQuery, который по сути, вроде как, делал тоже самое, но на своем языке.&lt;/p&gt;
  &lt;p id=&quot;Slk1&quot;&gt;Параллельно я нашел другой подход, который как раз мне понравился — через работу с самим NodeList, &lt;strong&gt;клонирование итемов&lt;/strong&gt; через &lt;code&gt;.cloneNode()&lt;/code&gt; и подстановка их в конец с помощью &lt;code&gt;.appendChild()&lt;/code&gt;.&lt;/p&gt;
  &lt;p id=&quot;6XIW&quot;&gt;Это и решает проблемы выше и даже, насколько я понял, работает в рамках прогрессивного улучшения, так как дополнительные итемы появляются только с подключением JS к файлу.&lt;/p&gt;
  &lt;figure id=&quot;HRJb&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/02/c0/02c0a670-bace-4112-a7e8-782a30094603.png&quot; width=&quot;427&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;3jYt&quot;&gt;Примерный алгоритм работы слайдера по краям:&lt;/p&gt;
  &lt;ol id=&quot;OjZU&quot;&gt;
    &lt;li id=&quot;9gsD&quot;&gt;Текущий &lt;code&gt;current&lt;/code&gt; слайд находится на краю массива, не важно в начале или в конце.&lt;/li&gt;
    &lt;li id=&quot;gySz&quot;&gt;Нажатие на кнопку в сторону «за» конец массива — на 1-м &lt;code&gt;&amp;lt;- влево&lt;/code&gt; или на 4-м (1-м клоне) &lt;code&gt;вправо -&amp;gt;&lt;/code&gt;, вызывает функцию замены позиции с 1-го на позицию клона или наоборот.&lt;/li&gt;
    &lt;li id=&quot;lvM5&quot;&gt;После замены срабатывает основная функция слайдера с анимацией смещения.&lt;/li&gt;
  &lt;/ol&gt;
  &lt;p id=&quot;GLxH&quot;&gt;Ну что, погнали.&lt;/p&gt;
  &lt;p id=&quot;8iWX&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;aVn4&quot;&gt;Собираем элементы&lt;/h3&gt;
  &lt;p id=&quot;Ca5K&quot;&gt;Для начала нам, естественно, нужно собрать элементы с которыми будем работать. Тут должно быть всё просто — используем &lt;code&gt;.querySelector()&lt;/code&gt; и &lt;code&gt;.querySelectorAll()&lt;/code&gt; для списков и работаем дальше. &lt;/p&gt;
  &lt;pre id=&quot;SqtQ&quot; data-lang=&quot;javascript&quot;&gt;const promoSection = document.querySelector(&amp;quot;.promo&amp;quot;);
const picSliderList = promoSection.querySelector(&amp;quot;.slider__list&amp;quot;);
let picSlides = picSliderList.querySelectorAll(&amp;quot;.slider__item&amp;quot;);
...&lt;/pre&gt;
  &lt;p id=&quot;GFKC&quot;&gt;Но не тут-то было.&lt;/p&gt;
  &lt;p id=&quot;WUeh&quot;&gt;В ходе работы над задачей я, возможно преждевременно, но познакомился с понятиями &lt;a href=&quot;https://developer.mozilla.org/ru/docs/Web/API/Node&quot; target=&quot;_blank&quot;&gt;Node&lt;/a&gt; и &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/NodeList&quot; target=&quot;_blank&quot;&gt;NodeList&lt;/a&gt; и тем, что они бывают двух типов — живые (live) и статичные (static). Это заставило на пол пути почти полностью переписать некоторые функции.&lt;/p&gt;
  &lt;p id=&quot;fJYe&quot;&gt;Как я уже писал выше, метод &lt;code&gt;.querySelectorAll()&lt;/code&gt; собирает элементы не в массив или обычный объект, а в специальный объект NodeList, который имеет свойство &lt;code&gt;read-only&lt;/code&gt;, то есть &lt;strong&gt;неизменяемый&lt;/strong&gt; или «статичный». &lt;/p&gt;
  &lt;pre id=&quot;TaIO&quot; data-lang=&quot;javascript&quot;&gt;console.log(picSlides) // выведет список из 3-х объектов
picSliderList.appendChild(&amp;quot;клон/объект&amp;quot;); // добавляем 4-й объект
console.log(picSlides) // всё равно выдаст список из 3-х объектов&lt;/pre&gt;
  &lt;p id=&quot;MvfB&quot;&gt;Для нас это не очень хорошо — мы планируем изменять количество элементов в контейнере и работать далее уже с &lt;strong&gt;изменённым&lt;/strong&gt; списком. Нам нужен «живой» NodeList или его подобие, который будет реагировать на изменения в DOM.&lt;/p&gt;
  &lt;p id=&quot;H91c&quot;&gt;В этом нам &lt;em&gt;может&lt;/em&gt; помочь свойство объекта Node — &lt;code&gt;.childNodes&lt;/code&gt;, которое &lt;strong&gt;возвращает все дочерние Node&lt;/strong&gt;, то бишь NodeList и он при этом «живой», то есть реагирует на изменения.&lt;/p&gt;
  &lt;pre id=&quot;g7lb&quot; data-lang=&quot;javascript&quot;&gt;const picSliderList = promoSection.querySelector(&amp;quot;.slider__list&amp;quot;);
let picSlides = picSliderList.childNodes;&lt;/pre&gt;
  &lt;p id=&quot;VDC1&quot;&gt;Мы, правда, быстро споткнёмся о нюанс — &lt;code&gt;.childNodes&lt;/code&gt; собирает еще и какую-то шелуху, которые не являются элементами, но являются Node’ами.&lt;/p&gt;
  &lt;figure id=&quot;Pb8c&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/00/03/000399a7-8763-471e-9737-af6b11447583.png&quot; width=&quot;508&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;GpPa&quot;&gt;Насколько я понял — это пробелы от переноса строки, с ними можно «хорошо» познакомиться, если начать работать с &lt;a href=&quot;https://blog.arkhelvetios.ru/block-model-flow-and-float#dxgN&quot; target=&quot;_blank&quot;&gt;inline-block кнопками&lt;/a&gt;, например. Или нет и это что-то другое, я тут не эксперт, не слушайте меня. В любом случае — нам оно не надо, нам надо только элементы.&lt;/p&gt;
  &lt;p id=&quot;mjyf&quot;&gt;Тут нас спасает другое свойство, про которое, кстати, упоминалось в JavaScript тренажёрах, но я вот не помню, было ли там про живые/статичные коллекции. Это свойство &lt;code&gt;.children&lt;/code&gt;, которое возвращает &lt;strong&gt;HTMLCollection &lt;/strong&gt;— живую коллекцию всех дочерних элементов указанного контейнера.&lt;/p&gt;
  &lt;p id=&quot;ze7p&quot;&gt;Насколько я понял — это немного другой вид данных отличный от NodeList, более «массивоподобный» (array-like object написано в MDN), который для наших целей идеально подходит. В итоге вот что получается:&lt;/p&gt;
  &lt;pre id=&quot;4SEA&quot; data-lang=&quot;javascript&quot;&gt;let picSlides = picSliderList.children;

console.log(picSlides) // 3 объекта
picSliderList.appendChild(&amp;quot;клон/объект&amp;quot;);
console.log(picSlides) // 4 объекта&lt;/pre&gt;
  &lt;p id=&quot;uHdD&quot;&gt;Хорошо! Не забываем собрать еще кнопки и пагинацию (кнопки-точки в углу) и переходим к функциональной части.&lt;/p&gt;
  &lt;p id=&quot;aFNI&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;2Ga6&quot;&gt;Клонируем слайды&lt;/h3&gt;
  &lt;p id=&quot;STv7&quot;&gt;Не смотря на то, что у текстового слайдера нет превью-итемов, они все за &lt;code&gt;overflow&lt;/code&gt;, ему всё равно надо сделать клона крайнего итема. Иначе при слайде вбок, будет моментальная замена, например, с 3-го на 1-й (или наоборот), а затем слайд-анимация ко 2-му, из-за чего всё ломается.&lt;/p&gt;
  &lt;p id=&quot;YaiZ&quot;&gt;Итак, сама функция клонирования:&lt;/p&gt;
  &lt;pre id=&quot;VTTS&quot; data-lang=&quot;javascript&quot;&gt;const addFirstToEnd = (itemsList) =&amp;gt; {
  let cloneItem = itemsList[0].cloneNode(true); //клон 1-го итема
  cloneItem.classList.remove(&amp;quot;current&amp;quot;); //убираем сласс current
  itemsList[0].parentNode.appendChild(cloneItem); //подставляем
}&lt;/pre&gt;
  &lt;section style=&quot;background-color:hsl(hsl(34,  84%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;kmW0&quot;&gt;Параметр true/false у &lt;code&gt;.cloneNode&lt;/code&gt; определяет копировать ли элемент вместе с внутренностями или только пустой элемент. А свойство &lt;code&gt;.parentNode&lt;/code&gt; обращается к родительскому node указанного элемента.&lt;/p&gt;
  &lt;/section&gt;
  &lt;p id=&quot;EYXm&quot;&gt;Тут очередная проблема, которую я не сразу заметил — для текстового слайдера нам хватит и одного клона, а вот для картинок получается, что нет. Одновременно в поле видимости слайдера с картинками у нас 3 слайда, просто 2 как превью. &lt;/p&gt;
  &lt;p id=&quot;0NBC&quot;&gt;Следовательно, для корректной работы нам надо клонировать все видимые слайды, то бишь вообще все. Два последних итема никогда не будут выбраны, но нужны только для отображения при &lt;code&gt;current&lt;/code&gt; на 1-м клоне.&lt;/p&gt;
  &lt;p id=&quot;v45u&quot;&gt;Возникает еще одна дилемма — требуется разное количество клонов. Можно забить и сделать одинаковое — текстовых тоже будет 6, просто 2 последних будут совсем мёртвым грузом. Но я решил доработать функцию, что б она могла делать разное количество клонов:&lt;/p&gt;
  &lt;pre id=&quot;miFO&quot; data-lang=&quot;javascript&quot;&gt;const addClonesToEnd = (clonesNumber, itemsList) =&amp;gt; {
  for (i = 0; i &amp;lt; clonesNumber; i++) {
    let cloneItem = itemsList[i].cloneNode(true);
    cloneItem.classList.remove(&amp;quot;current&amp;quot;);
    itemsList[i].parentNode.appendChild(cloneItem);
  }
}
addClonesToEnd(3, picSlides); // +2 превью
addClonesToEnd(1, textSlides);&lt;/pre&gt;
  &lt;p id=&quot;OvCH&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;TC0b&quot;&gt;Замена позиции&lt;/h3&gt;
  &lt;p id=&quot;VYld&quot;&gt;Это, наверное, не самое очевидное к чему следует приступать на данном этапе, но мне хотелось сначала понять, смогу ли я вообще реализовать такой слайдер, а уже потом что-то там двигать и анимировать.&lt;/p&gt;
  &lt;p id=&quot;ou4i&quot;&gt;Для проверки будем двигать не слайды, а вспомогательный класс &lt;code&gt;.current&lt;/code&gt;, обозначающий выбранный слайд. Благо менять классы у элементов мы уже умеем с помощью методов &lt;code&gt;.classList.add/remove&lt;/code&gt;. Сейчас вопрос не «Как», а «Куда двигать?».&lt;/p&gt;
  &lt;p id=&quot;7sMh&quot;&gt;Я решил подойди с точки зрения привязки элементов к их &lt;strong&gt;индексу&lt;/strong&gt; в коллекции. Несмотря на то, что у нас разная длина коллекций — 4 у текстового и 6 у картиночного, два последних клона в картиночном нас не интересуют, поэтому позиции во всех случаях у обоих слайдеров будут совпадать.&lt;/p&gt;
  &lt;p id=&quot;oIOt&quot;&gt;Получается, что у нас есть &lt;strong&gt;начальный&lt;/strong&gt;, который совпадает с текущим, &lt;strong&gt;конечный&lt;/strong&gt; индексы итемов и нам нужен еще &lt;strong&gt;следующий&lt;/strong&gt; индекс, который будет рассчитываться нажатием кнопки влево/вправо:&lt;/p&gt;
  &lt;pre id=&quot;qHNU&quot; data-lang=&quot;javascript&quot;&gt;let lastSlideIndex = textSlides.length - 1; // 0 - 1 - 2 - [3]
let currentSlideIndex = 0;
let nextSlideIndex = 1;&lt;/pre&gt;
  &lt;p id=&quot;XMnS&quot;&gt;Переходим к самому нажатию на кнопки. Функция нажатия должна высчитывать индекс следующего итема &lt;code&gt;nextSlideIndex&lt;/code&gt;, двигать слайд в направлении от текущего к следующему и после этого следующий становиться текущим. &lt;/p&gt;
  &lt;p id=&quot;kjqD&quot;&gt;При этом кнопки у нас две — одна двигает вправо, то бишь &lt;strong&gt;увеличивает&lt;/strong&gt; индекс, вторая же влево, то бишь индекс &lt;strong&gt;уменьшает&lt;/strong&gt;. Языком JS:&lt;/p&gt;
  &lt;pre id=&quot;RFnh&quot; data-lang=&quot;javascript&quot;&gt;buttonNext.addEventListener(&amp;quot;click&amp;quot;, () =&amp;gt; {
  nextSlideIndex = currentSlideIndex + 1; // -1 для buttonPrev
  
  picSlides[currentSlideIndex].classList.remove(&amp;quot;current&amp;quot;);
  textSlides[currentSlideIndex].classList.remove(&amp;quot;current&amp;quot;);
  picSlides[nextSlideIndex].classList.add(&amp;quot;current&amp;quot;);
  textSlides[nextSlideIndex].classList.add(&amp;quot;current&amp;quot;);
  
  currentSlideIndex = nextSlideIndex; // заменяем значение текущего
}&lt;/pre&gt;
  &lt;p id=&quot;8ZzB&quot;&gt;Визуально ничего не двигается (меняются размеры картинок только), зато двигается класс:&lt;/p&gt;
  &lt;figure id=&quot;3lEs&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/0e/c0/0ec025b1-d679-454b-9799-327748dd101a.gif&quot; width=&quot;440&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;QNER&quot;&gt;Быстро упираемся в проблему, когда нажимаем на кнопку влево и получаем &lt;code&gt;nextSlideIndex = -1&lt;/code&gt;, такого индекса нет, как и индекса 4, который мы поймаем после нажатия вправо на последнем слайде. &lt;/p&gt;
  &lt;p id=&quot;Xzqh&quot;&gt;В этот момент наступает время &lt;strong&gt;замены слайдов&lt;/strong&gt;! Я решил зайти через простую проверку условия — если &lt;code&gt;nextSlideIndex&lt;/code&gt; вне диапазона коллекции, то меняем слайды местами. А так как у нас первый и последний слайд-клон одинаковые, замена должна происходить без видимых последствий.&lt;/p&gt;
  &lt;p id=&quot;wC6i&quot;&gt;Для краткости и чтобы много раз не переписывать эти четыре строки с &lt;code&gt;classList.remove/add&lt;/code&gt; я вывел их в отдельную функцию &lt;code&gt;switchClasses()&lt;/code&gt;:&lt;/p&gt;
  &lt;pre id=&quot;Bv69&quot; data-lang=&quot;javascript&quot;&gt;buttonNext.addEventListener(&amp;quot;click&amp;quot;, () =&amp;gt; {
  nextSlideIndex = currentSlideIndex + 1; // = условно [4]
  
  if (nextSlideIndex &amp;gt; lastSlideIndex) { // для buttonPrev (next &amp;lt; 0)
    nextSlideIndex = 0;
    switchClasses();
    currentSlideIndex = nextSlideIndex; // заменяем значение текущего
    nextSlideIndex = currentSlideIndex + 1; // заново считаем next
  }
  
  switchClasses();
  
  currentSlideIndex = nextSlideIndex; // финально заменяем значение
}&lt;/pre&gt;
  &lt;p id=&quot;b4j3&quot;&gt;Внезапно для меня всё сработало! Выглядит, возможно, немного неказисто, зато работает — пока не трогаем. Переходим к переходам!&lt;/p&gt;
  &lt;p id=&quot;QBx5&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;Nc2x&quot;&gt;Плавно переходим&lt;/h3&gt;
  &lt;p id=&quot;xwQa&quot;&gt;Итак, теперь нам нужно натянуть на наш функциональный скелет движение не только класса, но и слайда целиком и еще сделать плавные переходы состояний у картинок — от маленьких полупрозрачных до больших непрозрачных.&lt;/p&gt;
  &lt;p id=&quot;9zuB&quot;&gt;Самый, эм… распространённый вариант из моих поисков на чистом JavaScript (без jQuery) — это использование свойства &lt;code&gt;.style&lt;/code&gt; к элементу. Этим способом мы прописываем элементу inline-стили в атрибут. &lt;/p&gt;
  &lt;pre id=&quot;3Nsb&quot; data-lang=&quot;javascript&quot;&gt;picSlider.style.transition = &amp;quot;transform 500ms ease-out&amp;quot;;
picSlider.style.transform = &amp;quot;translateX(-100px)&amp;quot;; // подвинет влево&lt;/pre&gt;
  &lt;p id=&quot;CH6q&quot;&gt;Код выше применит в HTML к указанному элементу атрибут &lt;code&gt;style&lt;/code&gt;:&lt;/p&gt;
  &lt;figure id=&quot;NSKS&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/0d/33/0d333e4b-3d29-4b5c-a7fe-ea293f963b67.png&quot; width=&quot;324&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;QzjO&quot;&gt;И это, в целом, то что нам нужно — подставим изменение стилей в функцию нажатия кнопки, в &lt;code&gt;translateX()&lt;/code&gt; подставим нужную величину сдвига для слайдера, а картинкам можно в CSS прописать &lt;code&gt;transition&lt;/code&gt; на размеры и непрозрачность и они сами будут плавно переходить от &lt;code&gt;.current&lt;/code&gt; и обратно.&lt;/p&gt;
  &lt;p id=&quot;jIiU&quot;&gt;Величину сдвига можно рассчитывать от индекса и размера итема, подставив через интерполяцию в значение свойства. Таким образом, у каждой позиции будет свой сдвиг. Условный пример:&lt;/p&gt;
  &lt;pre id=&quot;7DPF&quot; data-lang=&quot;javascript&quot;&gt;picSlider.style.transform: &amp;#x60;translateX(-${nextSlideIndex * offset}px)&amp;#x60;&lt;/pre&gt;
  &lt;p id=&quot;ikuz&quot;&gt;То есть, условно, [0]-й слайдер — сдвиг на 0 * 150 = 0px, [1]-й — сдвиг на 150px и так далее. На данном этапе я подсмотрел размер итемов в DevTools во вкладке Computed или можно самому посчитать &lt;code&gt;width + padding + border + margin&lt;/code&gt;, но об этом подробнее чуть позже.&lt;/p&gt;
  &lt;p id=&quot;etzK&quot;&gt;Получается, по итогу, что нам надо-то добавить несколько строк:&lt;/p&gt;
  &lt;pre id=&quot;6TJX&quot; data-lang=&quot;javascript&quot;&gt;buttonNext.addEventListener(&amp;quot;click&amp;quot;, () =&amp;gt; {
  nextSlideIndex = currentSlideIndex + 1;
  
  if (nextSlideIndex &amp;gt; lastSlideIndex) { /* замена, тоси-боси */ }
  
  picSlider.style.transition = &amp;quot;transform 500ms ease-out&amp;quot;;
  textSlider.style.transition = &amp;quot;transform 500ms ease-out&amp;quot;;
  picSlider.style.transform = &amp;#x60;translateX(-${nextSlideIndex * 141}px)&amp;#x60;;
  textSlider.style.transform = &amp;#x60;translateX(-${nextSlideIndex * 540}px)&amp;#x60;;
  switchClasses();
  
  currentSlideIndex = nextSlideIndex;
}&lt;/pre&gt;
  &lt;p id=&quot;DS6N&quot;&gt;Вуаля! Всё работает! Нет, правда! Слайды плавно двигаются, листаются. В конце коллекции происходит замена, как мы и хотели, и… идёт обратно?..&lt;/p&gt;
  &lt;figure id=&quot;NnWz&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/b7/54/b7549676-8cf2-47ab-aacd-6ec5cbce72d5.gif&quot; width=&quot;700&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;7wwK&quot;&gt;В принципе, можно оставить и так. Работает же? Работает. Даже, можно сказать, красиво — анимации итемов, плавно в обе стороны, все ок. Но я всё же решил доделать до изначально задуманного концепта.&lt;/p&gt;
  &lt;p id=&quot;YQYK&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;rRgo&quot;&gt;Асинхронность JS, переходы и анимация&lt;/h2&gt;
  &lt;p id=&quot;8j0t&quot;&gt;Первое что мне пришло в голову — надо обнулить &lt;code&gt;transition&lt;/code&gt; при замене в &lt;code&gt;if&lt;/code&gt;, добавить туда &lt;code&gt;transform&lt;/code&gt; к нулю и тогда, по идее, будет сначала производиться мгновенная замена с конца на начало, а пото-о-ом уже плавный переход на итоговый слайд! Но нет.&lt;/p&gt;
  &lt;p id=&quot;sTAl&quot;&gt;Во-первых, &lt;code&gt;transition&lt;/code&gt; у самих картинок, то бишь изменение размеров и непрозрачности, мы так просто не уберём, нужно обращаться к конкретному элементу — к картинке и еще &lt;code&gt;span&lt;/code&gt;&amp;#x27;у-кружочку на фоне.&lt;/p&gt;
  &lt;p id=&quot;2lyX&quot;&gt;Во-вторых, как оказалось, JavaScript хитрый язык на многих уровнях. Он вроде как однопоточный, то есть все инструкции выполняются по порядку, но при этом &lt;strong&gt;асинхронный&lt;/strong&gt;, то есть не совсем по порядку, могут и параллельно. &lt;/p&gt;
  &lt;p id=&quot;rZX0&quot;&gt;Что и случилось, в общем-то, с нашей заменой слайдов — JS выполнил всё, грубо говоря, одновременно. Он посчитал индексы, финальным оказался индекс [1] — к нему он и применяет &lt;code&gt;translateX()&lt;/code&gt;, из-за чего слайдер не «зациклился», а переместился в обратном направлении.&lt;/p&gt;
  &lt;section style=&quot;background-color:hsl(hsl(34,  84%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;ow6j&quot;&gt;Тут я полез разбираться и залез в очень глубокие дебри, в которые, на мой взгляд, пока рановато. Либо учить всё прям до момента понимания, на что я не был готов на данный момент (сидеть месяц над слайдером такое себе), либо искать какое-то другое решение, пусть и на 3-х костылях.&lt;/p&gt;
    &lt;p id=&quot;CEyP&quot;&gt;Я честно пытался разобраться для более изящного решения, начал вникать в асинхронность JS, в работу «стека вызовов», в контекст вызова и колбэки, в итоге в промисы и async/await. Но у меня не получилось, как бы я не пытался, я где-то сутки-двое сидел. На этом этапе просто не хватило знаний и опыта. Но я решил сделать по-своему! &lt;code&gt;:D&lt;/code&gt;&lt;/p&gt;
  &lt;/section&gt;
  &lt;p id=&quot;HlPX&quot;&gt;Итак, не победив асинхронность я решил встать на её сторону — пусть выполняется одновременно, тогда будем мучить сами переходы.&lt;/p&gt;
  &lt;p id=&quot;raoI&quot;&gt;Я нашел несколько примеров подобных слайдеров, большинство из которых были, сука, на jQuery, но именно это мне и помогло. Я решил прям взять и скопировать один из вариантов (правда с 2-мя клонами) в CodePen и проинспектировать в DevTools как они себя ведут.&lt;/p&gt;
  &lt;p id=&quot;fKQw&quot;&gt;Внезапно для себя я кое-что обнаружил! Вот как ведёт себя переход слайдера у меня, внимание на &lt;code&gt;translateX()&lt;/code&gt;:&lt;/p&gt;
  &lt;figure id=&quot;LqHF&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/3f/c2/3fc21b1a-dacd-45c2-a80f-8de29d6aced3.gif&quot; width=&quot;644&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;dcvm&quot;&gt;А вот как ведёт себя переход в примере на jQuery, который я нашел на &lt;a href=&quot;https://stackoverflow.com/questions/15876754/infinity-loop-slider-concepts&quot; target=&quot;_blank&quot;&gt;stackoverflow&lt;/a&gt;:&lt;/p&gt;
  &lt;figure id=&quot;64t1&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/6f/ed/6fedca29-4d60-4915-a7f2-8f32e06b7260.gif&quot; width=&quot;392&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;5x4D&quot;&gt;Мой переход применяет новое значение мгновенно, в то время как переход в примере применяет какое-то колдовство. В этот момент я полез изучать как работают анимации в JavaScript.&lt;/p&gt;
  &lt;p id=&quot;THUK&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;vRCs&quot;&gt;Анимация против inline-переходов&lt;/h3&gt;
  &lt;p id=&quot;KEYq&quot;&gt;Оказалось, что используемый в примере на jQuery метод (?) &lt;code&gt;:animate()&lt;/code&gt; это не то же самое, что навешать &lt;code&gt;.style.tranform&lt;/code&gt; на элемент. Это именно функция. Значит и в нативном JS должно быть что-то подобное и оно действительно есть!&lt;/p&gt;
  &lt;p id=&quot;V8Vj&quot;&gt;И тут два пути. Более сложный вариант через создание функции анимации, буквально с нуля, используя &lt;code&gt;requestAnimationFrame()&lt;/code&gt;, которая принимает колбэк функцию с расчётом Кривой Безье для timing-функции (которые ease/-in/-out), функцией отрисовки и условием продолжительности. Или…&lt;/p&gt;
  &lt;p id=&quot;Ej1x&quot;&gt;Или использовать более простой &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Element/animate&quot; target=&quot;_blank&quot;&gt;метод&lt;/a&gt; &lt;code&gt;.animate()&lt;/code&gt; DOM элемента, который принимает массив с кейфреймами, работающие аналогично как в CSS, и параметры анимации, которые тоже совпадают с хорошо знакомыми свойствами CSS &lt;code&gt;animation-duration&lt;/code&gt;, &lt;code&gt;animation-timing&lt;/code&gt; и т. д.&lt;/p&gt;
  &lt;p id=&quot;k7CN&quot;&gt;Я выбрал второй вариант и мне не стыдно. Выглядит все вот так:&lt;/p&gt;
  &lt;pre id=&quot;SVkS&quot; data-lang=&quot;javascript&quot;&gt;picSlider.animate([
  {transform: &amp;#x60;translateX(-${currentSlideIndex * 141}px)&amp;#x60;}, // от или 0%
  {transform: &amp;#x60;translateX(-${nextSlideIndex * 141}px)&amp;#x60;} // до или 100%
  ], {
  duration: 500,
  easing: &amp;quot;ease-out&amp;quot;,
  fill: &amp;quot;forwards&amp;quot;
});&lt;/pre&gt;
  &lt;p id=&quot;gUuD&quot;&gt;Вся эта запись эквивалентна созданию &lt;code&gt;@keyframes&lt;/code&gt; в CSS и применению её к элементу по классу, но в JS мы можем запрограммировать её вызов ну и подставить интерполяцией значения, что удобно.&lt;/p&gt;
  &lt;p id=&quot;mjNp&quot;&gt;Но самое главное — эта анимация работает, как бы, «покадрово», так же как анимация из примера — применяя в короткие промежутки времени разные значения из указанного интервала. Я чёрт знает как это на нормальном языке объяснить, надеюсь вы поняли. &lt;code&gt;:D&lt;/code&gt;&lt;/p&gt;
  &lt;p id=&quot;qDUo&quot;&gt;А следствие всего этого то, что таким образом анимация обрабатывается &lt;strong&gt;последовательно&lt;/strong&gt;! Теперь если мы запихнём &lt;code&gt;.animate()&lt;/code&gt; c нулевым &lt;code&gt;duration&lt;/code&gt; в условие для замены, то он сначала заменит, а потом проиграет следующий &lt;code&gt;.animate()&lt;/code&gt; с плавным переходом!&lt;/p&gt;
  &lt;pre id=&quot;akrm&quot; data-lang=&quot;javascript&quot;&gt;buttonNext.addEventListener(&amp;quot;click&amp;quot;, () =&amp;gt; {
  nextSlideIndex = currentSlideIndex + 1;
  
  if (nextSlideIndex &amp;gt; lastSlideIndex) {
    nextSlideIndex = 0;
  
    switchClasses();
  
    picSlider.animate([
      {transform: &amp;#x60;translateX(-${currentSlideIndex * 141}px)&amp;#x60;},
      {transform: &amp;#x60;translateX(-${nextSlideIndex * 141}px)&amp;#x60;}
      ], { duration: 0 }
    );
    /* ... textSlider аналогично */

    currentSlideIndex = nextSlideIndex;
    nextSlideIndex = currentSlideIndex + 1;
  }
  
  switchClasses();

  picSlider.animate([
    {transform: &amp;#x60;translateX(-${currentSlideIndex * 141}px)&amp;#x60;},
    {transform: &amp;#x60;translateX(-${nextSlideIndex * 141}px)&amp;#x60;}
    ], { duration: 500, easing: &amp;quot;ease-out&amp;quot;, fill: &amp;quot;forwards&amp;quot;}
  );  
  /* ... textSlider аналогично */
  
  currentSlideIndex = nextSlideIndex;
}&lt;/pre&gt;
  &lt;p id=&quot;JW7H&quot;&gt;Смещение работает с правильной заменой, без асинхронной подставы! Но, чёрт возьми, у нас появился еще один неприятный нюанс. Смещение работает идеально, но анимация самих итемов при смене класса &lt;code&gt;.current&lt;/code&gt; работает всё равно в асинхронном формате.&lt;/p&gt;
  &lt;figure id=&quot;MsFA&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/00/27/00276fa7-73d9-4a3c-997e-a9b9b4ab21fe.gif&quot; width=&quot;700&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;z3Ds&quot;&gt;Тут я совсем уже отчаялся, вернулся опять к теме async/await, потом попытался сделать через два клона — спереди и сзади коллекции, сделать замену через &lt;code&gt;transitionend&lt;/code&gt;, но всё не получалось или приводило в итоге к тому же. &lt;/p&gt;
  &lt;p id=&quot;jzrK&quot;&gt;На следующее утро решил вернуться к &lt;code&gt;.animate()&lt;/code&gt; и пойти просто в лоб — будем анимировать всё что двигается! А что не двигается — двигать и анимировать. Соберём все анимируемые элементы и пропишем им анимацию отдельно.&lt;/p&gt;
  &lt;p id=&quot;NoR8&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;ild7&quot;&gt;Собираем всё для анимации&lt;/h3&gt;
  &lt;p id=&quot;aaWY&quot;&gt;Для начала надо собрать в кучу всю информацию — какие элементы изменяются и какие параметры задействованы. Тут многое зависит от вёрстки и в общем от самой идеи анимации.&lt;/p&gt;
  &lt;p id=&quot;ascR&quot;&gt;У меня каждый итем это &lt;code&gt;&amp;lt;li&amp;gt;&lt;/code&gt;, внутри в текстовом, внезапно — текст и кнопка, а внутри картиночного — картинка &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; и &lt;code&gt;&amp;lt;span&amp;gt;&lt;/code&gt;, имеющий роль кружочка. &lt;/p&gt;
  &lt;p id=&quot;QD9W&quot;&gt;Я сначала сверстал его через &lt;code&gt;::before&lt;/code&gt;, как и полагается декорации, но с псевдоэлементами туго работает JS, так как псевдоэлемент на то и &lt;em&gt;псевдо-&lt;/em&gt; и является элементом стилей, а не вёрстки.&lt;/p&gt;
  &lt;pre id=&quot;2OT4&quot; data-lang=&quot;html&quot;&gt;&amp;lt;!-- без div-обёрток --&amp;gt;
&amp;lt;ul class=&amp;quot;slider-text__list&amp;quot;&amp;gt; &amp;lt;!-- слайды текста --&amp;gt;
  &amp;lt;li class=&amp;quot;slider-text__item current&amp;quot;&amp;gt; ... &amp;lt;/li&amp;gt;
  &amp;lt;li class=&amp;quot;slider-text__item&amp;quot;&amp;gt; ... &amp;lt;/li&amp;gt;
  ...
&amp;lt;/ul&amp;gt;
...
&amp;lt;ul class=&amp;quot;slider__list&amp;quot;&amp;gt; &amp;lt;!-- слайды картинок --&amp;gt;
  &amp;lt;li class=&amp;quot;slider__item current&amp;quot;&amp;gt;
    &amp;lt;img src=&amp;quot;pic1.png&amp;quot;&amp;gt; &amp;lt;!-- картинка --&amp;gt;
    &amp;lt;span&amp;gt;&amp;lt;/span&amp;gt; &amp;lt;!-- кружок на фоне --&amp;gt;
  &amp;lt;/li&amp;gt;
  &amp;lt;li class=&amp;quot;slider__item&amp;quot;&amp;gt; ... &amp;lt;/li&amp;gt;
  ...
&amp;lt;/ul&amp;gt;&lt;/pre&gt;
  &lt;p id=&quot;wx3Z&quot;&gt;Анимация у меня задумана следующая:&lt;/p&gt;
  &lt;ol id=&quot;MQEk&quot;&gt;
    &lt;li id=&quot;SQks&quot;&gt;Текстовый &lt;code&gt;.slider-text__item&lt;/code&gt; итем меняет размер &lt;code&gt;scale()&lt;/code&gt; и непрозрачность &lt;code&gt;opacity&lt;/code&gt;, имитируя поведение картиночного итема.&lt;/li&gt;
    &lt;li id=&quot;BI8s&quot;&gt;Картиночный &lt;code&gt;.slider__item&lt;/code&gt; меняет непрозрачность &lt;code&gt;opacity&lt;/code&gt;, а так же по макету у них разные поля &lt;code&gt;padding&lt;/code&gt; (для «вылета» кнопок на &lt;code&gt;.current&lt;/code&gt;).&lt;/li&gt;
    &lt;li id=&quot;4x5s&quot;&gt;Картинка &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; в итеме меняет размеры &lt;code&gt;width&lt;/code&gt; и &lt;code&gt;height&lt;/code&gt;.&lt;/li&gt;
    &lt;li id=&quot;j1sR&quot;&gt;Фоновый кружок &lt;code&gt;&amp;lt;span&amp;gt;&lt;/code&gt; меняет размеры &lt;code&gt;width&lt;/code&gt; и &lt;code&gt;height&lt;/code&gt;.&lt;/li&gt;
  &lt;/ol&gt;
  &lt;p id=&quot;gw5B&quot;&gt;Сразу, наверное, поясню — я пробовал сделать через &lt;code&gt;scale()&lt;/code&gt; на картиночном итеме &lt;code&gt;.slider__item&lt;/code&gt;, получалось хреново — размер уменьшается только визуально, при этом занятое место под элемент не уменьшается, нам же надо именно перерасчет ширины итема. &lt;/p&gt;
  &lt;p id=&quot;aQxU&quot;&gt;При этом еще нужно заметить, что при активации у нас анимируется сразу несколько итемов — текущие с &lt;code&gt;.current&lt;/code&gt; уменьшаются, а следующие увеличиваются. То бишь одновременно, помимо еще самого смещения слайдера, происходит 4 анимации с итемами.&lt;/p&gt;
  &lt;p id=&quot;P2mm&quot;&gt;Окей, то есть нам надо сделать &lt;code&gt;.animate()&lt;/code&gt; для всех элементов еще и в два направления — от маленького к большому и обратно. Получается, нам нужно каждый раз еще получать текущий и следующий элемент, точнее пачку элементов, чтобы применять анимации именно к ним. Кошмар. &lt;/p&gt;
  &lt;p id=&quot;jnrI&quot;&gt;Но ладно. Сначала попробуем, а потом будем решать. Итого нам надо собрать:&lt;/p&gt;
  &lt;pre id=&quot;o2Ad&quot; data-lang=&quot;javascript&quot;&gt;/* элементы текущих слайдов */
let textItem = textSlides[currentSlideIndex]; // текстовый
let picItem = picSlides[currentSlideIndex]; // картиночный
let picItemImg = picItem.children[0]; // сама картинка &amp;lt;img&amp;gt;
let picItemSpan = picItem.children[1]; // &amp;lt;span&amp;gt; кружочек

/* элементы следующих слайдов */
let nextTextItem = textSlides[nextSlideIndex];
let nextPicItem = picSlides[nextSlideIndex];
let nextPicItemImg = nextPicItem.children[0];
let nextPicItemSpan = nextPicItem.children[1];&lt;/pre&gt;
  &lt;p id=&quot;5QCJ&quot;&gt;Дальше, так как индексы постоянно меняются, нам нужно при каждом нажатии кнопки эти переменные переназначать, чтобы анимация корректно применялась к текущим позициям. Запихивать эти же строки по 2 раза в каждую кнопку как-то расточительно, поэтому я решил вывести это в отдельную функцию:&lt;/p&gt;
  &lt;pre id=&quot;HO30&quot; data-lang=&quot;javascript&quot;&gt;const getItemsByIndex = () =&amp;gt; {
  textItem = textSlides[currentSlideIndex];
  picItem = picSlides[currentSlideIndex];
  picItemImg = picItem.children[0];
  picItemSpan = picItem.children[1];
  
  nextTextItem = textSlides[nextSlideIndex];
  nextPicItem = picSlides[nextSlideIndex];
  nextPicItemImg = nextPicItem.children[0];
  nextPicItemSpan = nextPicItem.children[1];
};&lt;/pre&gt;
  &lt;pre id=&quot;OpJ5&quot; data-lang=&quot;javascript&quot;&gt;buttonNext.addEventListener(&amp;quot;click&amp;quot;, () =&amp;gt; {
  nextSlideIndex = currentSlideIndex + 1;
  
  if (nextSlideIndex &amp;gt; lastSlideIndex) {
    nextSlideIndex = 0;
    
    getItemsByIndex(); // получаем элементы по текущим индексам
    switchClasses();
  
    picSlider.animate(/* 0ms анимация слайдера */);
    textSlider.animate(/* 0ms анимация слайдера */);
    /* ... анимируем замену всего остального */

    currentSlideIndex = nextSlideIndex;
    nextSlideIndex = currentSlideIndex + 1;
  }
  
  getItemsByIndex();
  switchClasses();

  picSlider.animate(/* анимация слайдера */);
  textSlider.animate(/* анимация слайдера */);
  /* ... анимируем плавно всё остальное */

  currentSlideIndex = nextSlideIndex;
}&lt;/pre&gt;
  &lt;p id=&quot;4DbE&quot;&gt;Получается уже нечто монструозное, даже с комментариями. Итак, что дальше? Каждому элементу теперь нужно применить &lt;code&gt;.animate()&lt;/code&gt; со своими параметрами. Параметры можно взять опять во вкладке Computed, давайте попробуем, пойдем по порядку:&lt;/p&gt;
  &lt;pre id=&quot;xnhG&quot; data-lang=&quot;javascript&quot;&gt;textItem.animate([
  {transform: scale(1), opacity: 1},
  {transform: scale(0.5), opacity: 0.5}
  ], {duration: 500, easing: &amp;quot;ease-out&amp;quot;, fill: &amp;quot;forwards&amp;quot;}
);
picItem.animate(
  {padding: 0 20px, opacity: 1},
  {padding: 0 5px, opacity: 0.5}
  ], {duration: 500, easing: &amp;quot;ease-out&amp;quot;, fill: &amp;quot;forwards&amp;quot;}
)
picItemImg.animate(
  {width: 306px, height: 507px}, ...&lt;/pre&gt;
  &lt;p id=&quot;fnSl&quot;&gt;Да ну нахрен! Это только три элемента из восьми и только для плавного 500ms перехода без замены. А это еще надо воткнуть в функцию на кнопку! Ужас!&lt;/p&gt;
  &lt;p id=&quot;JNB8&quot;&gt;Меняем план — выводим все анимации в отдельную функцию и стараемся максимально оптимизировать процесс.&lt;/p&gt;
  &lt;p id=&quot;cPYg&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;dXVH&quot;&gt;Получаем Сomputed значения свойств&lt;/h3&gt;
  &lt;p id=&quot;OXs0&quot;&gt;Мне изначально немного свербило в голове, что приходится что-то калькулировать из DevTools и подставлять это в код. То есть, по сути, я брал значения из JavaScript в браузере и вставлял к себе в JavaScript. Может быть JavаматьегоScript сам умеет находить нужные ему циферки?&lt;/p&gt;
  &lt;p id=&quot;EORC&quot;&gt;И оказывается умеет! Есть несколько способов получить свойства элемента, но мне первым попался, да и больше понравился, вариант использования функции &lt;code&gt;getComputedStyle()&lt;/code&gt;, которая принимает элемент и возвращает огромный объект &lt;code&gt;CSSStyleDeclaration&lt;/code&gt; со всеми свойствами элемента, коих аж 342.&lt;/p&gt;
  &lt;figure id=&quot;nLYL&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/75/dc/75dc3895-a181-4b41-8e70-1ec4753cd7a2.png&quot; width=&quot;288&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;klSa&quot;&gt;У этой функции свои нюансы, например, она реагирует на свойство &lt;code&gt;box-sizing&lt;/code&gt; и по итогу в &lt;code&gt;width&lt;/code&gt; выдаёт значение суммы &lt;code&gt;width&lt;/code&gt; и &lt;code&gt;padding&lt;/code&gt; если стоит значение &lt;code&gt;border-box&lt;/code&gt;. Еще я в процессе работы заметил проблему с &lt;code&gt;height&lt;/code&gt; — сюда в сумму уходит каким-то хреном &lt;code&gt;line-height&lt;/code&gt; из-за чего нормально посчитать высоту итема с текстом будет трудно, но благо нам она и не нужна оказалась.&lt;/p&gt;
  &lt;p id=&quot;PSee&quot;&gt;Что это значит для нас? У нас есть элементы в разных состояниях, с разными свойствами — мы можем просто собрать с них все стили и применять их как состояния в анимации. На примере текстового итема:&lt;/p&gt;
  &lt;pre id=&quot;x4rl&quot; data-lang=&quot;javascript&quot;&gt;/* собираем стили состояний */
const currentTextItemStyles = getComputedStyle(textItem); //&amp;quot;большой&amp;quot;
const defaultTextItemStyles = getComputedStyle(nextTextItem); //&amp;quot;маленький&amp;quot;

/* делаем массивы кейфреймов */
const textItemIncrease = [defaultTextItemProps, currentTextItemProps];
const textItemDecrease = [currentTextItemProps, defaultTextItemProps];

/* анимируем используя кейфреймы */
textItem.animate(textItemDecrease, {duration: 500, ...}) // уменьшаем
nextTextItem.animate(textItemIncrease, {duration: 500, ...}) // увеличиваем&lt;/pre&gt;
  &lt;p id=&quot;UZKB&quot;&gt;Отлично! Уже значительно сократили писанину. Но меня на этом моменте смутило, что мы используем в анимации четыре раза два огромных массива по 300+ свойств. А это только один элемент. Нам же по сути нужны 2-3 свойства в каждой. Я решил попробовать избавиться от лишнего.&lt;/p&gt;
  &lt;p id=&quot;hYzR&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;Dh5P&quot;&gt;Отсеиваем лишние свойства&lt;/h3&gt;
  &lt;p id=&quot;QcS2&quot;&gt;Сам объект &lt;code&gt;CSSStyleDeclaration&lt;/code&gt; хранит в себе, в том числе, свойства в виде пар «свойство — значение». Я подумал было бы круто их как-то достать, именно те, что мне нужны. Как достать значения я прекрасно знал — по индексу или по ключу. А можно ли как-то вытянуть именно пару ключ-значение?&lt;/p&gt;
  &lt;p id=&quot;d7hE&quot;&gt;Можно, конечно! Используя хитрую функцию &lt;code&gt;.reduce()&lt;/code&gt;, которая, как бы, разбирает объект или массив по составляющим, используя колбэк функцию, где прописывается по каким условиям делать разбор.&lt;/p&gt;
  &lt;section style=&quot;background-color:hsl(hsl(34,  84%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;D2pj&quot;&gt;В поисках я нашёл еще &lt;a href=&quot;https://dev.to/rajnishkatharotiya/pick-desired-key-value-pair-from-an-object-48aa&quot; target=&quot;_blank&quot;&gt;более хитрую конструкцию&lt;/a&gt; с применением функции &lt;code&gt;.reduce()&lt;/code&gt;, на которую натурально минут 40 сидел и просто пялился, тупо чтобы понять что она вообще делает. А делает она как раз то, что мне надо — возвращает массив пар ключ-значение по заданным ключам.&lt;/p&gt;
  &lt;/section&gt;
  &lt;p id=&quot;1nPU&quot;&gt;Сама конструкция работает немного в обратную сторону — разбирается массив с искомыми ключами, но в контексте функции с объектом, в котором проверяется наличие этих ключей и функция возвращает объект с найденными ключами в паре со значениями. Завернул вам, блять, в шаурму — держите! &lt;/p&gt;
  &lt;figure id=&quot;oOCY&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/6d/87/6d876638-db35-48e9-b88e-cbbe727c81a6.jpeg&quot; width=&quot;700&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;SBI3&quot;&gt;Короче, я её трансформировал для себя в более понятном (надеюсь) виде. Занимает может и не одну строчку, зато переведено с квантово-индусского:&lt;/p&gt;
  &lt;pre id=&quot;r4OL&quot; data-lang=&quot;javascript&quot;&gt;const getElementProps = (element, keys) =&amp;gt; {
  elementStyles = getComputedStyle(element);
  return keys.reduce(
    (props, key) =&amp;gt; {
      if (key in elementStyles) {
        props[key] = elementStyles[key];
        return props;
      }
    }, {/* initialValue */} // пустой объект для сбора пар
  )};&lt;/pre&gt;
  &lt;p id=&quot;z7jL&quot;&gt;Итак, разбираемся что происходит:&lt;/p&gt;
  &lt;ol id=&quot;l0Jl&quot;&gt;
    &lt;li id=&quot;XmT0&quot;&gt;Функция &lt;code&gt;getElementProps()&lt;/code&gt; принимает элемент и массив с ключами искомых свойств вида &lt;code&gt;[&amp;quot;width&amp;quot;, &amp;quot;height&amp;quot;, ... ]&lt;/code&gt;.&lt;/li&gt;
    &lt;li id=&quot;mJjl&quot;&gt;Элементу находим все стили через &lt;code&gt;getComputedStyle()&lt;/code&gt; и записываем в локальную переменную &lt;code&gt;elementStyles&lt;/code&gt;.&lt;/li&gt;
    &lt;li id=&quot;sjWu&quot;&gt; В возврат &lt;code&gt;return&lt;/code&gt; (можно и отдельно) записываем &lt;code&gt;.reduce()&lt;/code&gt; функцию, которая пройдется по нашему массиву искомых ключей.&lt;/li&gt;
    &lt;li id=&quot;DhKz&quot;&gt;Функция &lt;code&gt;.reduce()&lt;/code&gt; принимает два аргумента — анонимную (не названную) колбэк функцию и &lt;code&gt;initialValue&lt;/code&gt; — пустой объект, куда будут записываться возвраты &lt;code&gt;return&lt;/code&gt; колбэк функции, то бишь пары ключ-значение.&lt;/li&gt;
    &lt;li id=&quot;jCuX&quot;&gt;Колбэк принимает два аргумента — аккумулятор &lt;code&gt;props&lt;/code&gt;, куда записывается каждый результат &lt;code&gt;return&lt;/code&gt; колбэка и обрабатываемый в одной итерации элемент &lt;code&gt;key&lt;/code&gt;. По сути, это всё такой хитрый эквивалент &lt;code&gt;for (key of keys)&lt;/code&gt;.&lt;/li&gt;
    &lt;li id=&quot;pWIx&quot;&gt;Внутри колбэк функции в условии проверяется наличие ключа key, например «width», в объекте через оператор in и в случае нахождения записывает значение по ключу в аккумулятор.&lt;/li&gt;
  &lt;/ol&gt;
  &lt;p id=&quot;qw64&quot;&gt;В итоге у нас получается вожделенный объект нужных нам свойств! На примере картиночного слайдера — нам нужны размеры &lt;code&gt;width&lt;/code&gt; и &lt;code&gt;height&lt;/code&gt; для картинки &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; и кружочка &lt;code&gt;&amp;lt;span&amp;gt;&lt;/code&gt;, потом &lt;code&gt;opacity&lt;/code&gt; для итема и еще &lt;code&gt;margin-right&lt;/code&gt; для расчёта смещения. Получается:&lt;/p&gt;
  &lt;pre id=&quot;Q9nX&quot; data-lang=&quot;javascript&quot;&gt;const picItemProps = [&amp;quot;width&amp;quot;, &amp;quot;height&amp;quot;, &amp;quot;opacity&amp;quot;, &amp;quot;marginRight&amp;quot;];

const currentPicItemProps = getElementProps(picItem, picItemProps);
const currentPicItemImgProps = getElementProps(picItemImg, picItemProps);
const currentPicItemSpanProps = getElementProps(picItemSpan, picItemProps);
/* аналогично для default состояния */&lt;/pre&gt;
  &lt;figure id=&quot;nNZx&quot; class=&quot;m_original&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/b7/ab/b7ab63df-3636-4747-beb9-621943e65497.png&quot; width=&quot;545&quot; /&gt;
    &lt;figcaption&gt;Пример что в итоге в currentPicItemProps&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;S29G&quot;&gt;А для смещения нам нужно только численное значения ширины &lt;code&gt;width&lt;/code&gt; и отступа &lt;code&gt;margin&lt;/code&gt;, без &lt;code&gt;px&lt;/code&gt;, так как мы потом будем подставлять его через интерполяцию в строку. Получаем его из наших пропсов с помощью функции &lt;code&gt;parseInt()&lt;/code&gt;:&lt;/p&gt;
  &lt;pre id=&quot;nttn&quot; data-lang=&quot;javascript&quot;&gt;const picSlideOffset = 
  parseInt(defaultPicItemProps.width) // не помещается :D
  + parseInt(defaultPicItemProps.marginRight); // = 101 + 40 = 141&lt;/pre&gt;
  &lt;p id=&quot;y5F6&quot;&gt;Аналогично делаем для всех четырёх элементов и двух состояний, собирая таким образом такую, условную базу кейфреймов для анимации. &lt;/p&gt;
  &lt;p id=&quot;27nK&quot;&gt;Еще для краткости и удобства можем собрать в одном месте наши параметры анимации, которых у нас всего два, но использоваться они будут очень часто:&lt;/p&gt;
  &lt;pre id=&quot;HxRb&quot; data-lang=&quot;javascript&quot;&gt;const instant = {duration: 0, fill: &amp;quot;forwards&amp;quot;}; // для замены
const ease500 = {duration: 500, easing: &amp;quot;ease-out&amp;quot;, fill: &amp;quot;forwards&amp;quot;};&lt;/pre&gt;
  &lt;p id=&quot;XW4I&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;lnEY&quot;&gt;Финальная подстановка&lt;/h3&gt;
  &lt;p id=&quot;6N8G&quot;&gt;Итак, у нас есть все действительные значения, записанные в кейфреймы, осталось дописать функции анимации. Продолжим на примере картиночного слайдера, так как он по сложнее.&lt;/p&gt;
  &lt;p id=&quot;pMPS&quot;&gt;Для начала сразу решим вопрос со смещением слайдера. Я не смог придумать как изящно запихнуть кейфреймы с интерполяцией, поэтому сделал функцию, которая просто сама уже подставит нужный оффсет и вернёт весь кейфрейм:&lt;/p&gt;
  &lt;pre id=&quot;qASG&quot; data-lang=&quot;javascript&quot;&gt;const moveContainer = (offset) =&amp;gt; {
  return [
    {transform: &amp;#x60;translateX(-${currentSlideIndex * offset}px)&amp;#x60;},
    {transform: &amp;#x60;translateX(-${nextSlideIndex * offset}px)&amp;#x60;}
  ]};&lt;/pre&gt;
  &lt;p id=&quot;92uZ&quot;&gt;И далее в &lt;code&gt;.animate()&lt;/code&gt; как аргумент подставляем эту функцию с нужным оффсетом. Остальные &lt;code&gt;.animate()&lt;/code&gt; функции принимают уже константы из нашей базы и работают с ними.&lt;/p&gt;
  &lt;p id=&quot;UL1z&quot;&gt;Я также для сокращения писанины решил вывести в отдельную функцию все анимации из кнопки и чтобы функция была универсальной — будем передавать в неё параметры анимации в зависимости от ситуации. Таким образом функция подойдет и в замене и в плавном переходе:&lt;/p&gt;
  &lt;pre id=&quot;IGzB&quot; data-lang=&quot;javascript&quot;&gt;const itemsAnimation = (timing) =&amp;gt; {
  textSlider.animate(moveContainer(textSlideOffset), timing);
  picSlider.animate(moveContainer(picSlideOffset), timing);
  
  textItem.animate(textItemDecrease, timing);
  picItem.animate(picItemOpacityOff, timing);
  picItemImg.animate(picItemImgDecrease, timing);
  picItemSpan.animate(picItemSpanDecrease, timing);
  
  nextTextItem.animate(textItemIncrease, timing);
  nextPicItem.animate(picItemOpacityOn, timing);
  nextPicItemImg.animate(picItemImgIncrease, timing);
  nextPicItemSpan.animate(picItemSpanIncrease, timing);
}&lt;/pre&gt;
  &lt;p id=&quot;upC6&quot;&gt;А в кнопке у нас остаётся только:&lt;/p&gt;
  &lt;pre id=&quot;rDhl&quot; data-lang=&quot;javascript&quot;&gt;buttonNext.addEventListener(&amp;quot;click&amp;quot;, () =&amp;gt; {
  nextSlideIndex = currentSlideIndex + 1;
  
  if (nextSlideIndex &amp;gt; lastSlideIndex) {
    nextSlideIndex = 0;
    
    getItemsByIndex();
    itemsAnimation(instant);
    switchClasses();
  
    currentSlideIndex = nextSlideIndex;
    nextSlideIndex = currentSlideIndex + 1;
  }
  
  getItemsByIndex();
  itemsAnimation(ease500);
  switchClasses();

  currentSlideIndex = nextSlideIndex;
}&lt;/pre&gt;
  &lt;p id=&quot;MD7W&quot;&gt;&lt;strong&gt;А вот, в общем-то, и всё&lt;/strong&gt;. Слайдер готов в том виде, в котором я изначально хотел. Я у себя в коде еще немного намудрил с выведением отдельно функций в кнопке &lt;code&gt;swapSlides()&lt;/code&gt; и &lt;code&gt;moveSlider()&lt;/code&gt; — которые еще чуть укорачивают запись.&lt;/p&gt;
  &lt;p id=&quot;zAMC&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;sph1&quot;&gt;Остальные задачи&lt;/h2&gt;
  &lt;p id=&quot;Qe4r&quot;&gt;Остались еще две периферийные задачи — пагинация из кнопок-точек в углу, с которой я тоже немножко повозился, но задача значительно легче уже показалась. И, собственно, замена стиля сайта при слайде, что меня изначально и привлекло, но на практике оказалось легчайшей задачей в данном вопросе.&lt;/p&gt;
  &lt;p id=&quot;p2II&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;kxXz&quot;&gt;Пагинация&lt;/h3&gt;
  &lt;p id=&quot;zjac&quot;&gt;Быстренько добьем эти задачки. Начнём с пагинации. Основная проблема у нас состоит в том, что точек всего три, сколько и не клонированных слайдов, то есть изначальная длинна коллекции.&lt;/p&gt;
  &lt;p id=&quot;04KT&quot;&gt;Это значит, что у нас первая точка должна обозначать и 1-й и 4-й слайд и, желательно, не перемещаться между ними при нажатии. При этом нужно не сломать всё остальное, то есть трогать расчёт индексов нельзя.&lt;/p&gt;
  &lt;p id=&quot;tNct&quot;&gt;Для начала навесим на кнопки функции на клик. Кнопок у нас три, но они однотипные — номер кнопки ведёт к номеру слайда. Тут прям напрашивается цикл и его мы и применим. &lt;/p&gt;
  &lt;pre id=&quot;C6TN&quot; data-lang=&quot;javascript&quot;&gt;for (let i = 0; i &amp;lt; buttonsDots.length; i++) {
  buttonsDots[i].addEventListener(&amp;quot;click&amp;quot;, () =&amp;gt; {
    nextSlideIndex = i; // номер кнопки от i = 0 равно индексу слайда
    
    getItemsByIndex();
    itemsAnimation(ease500);
    switchClasses();
    
    currentSlideIndex = nextSlideIndex;
});&lt;/pre&gt;
  &lt;p id=&quot;DK8m&quot;&gt;Еще надо сразу учесть проблему в случае позиции слайдера на клоне (4-м слайде) и нажатии, например на 3-й слайд. С кодом выше анимация будет влево, что немного неожиданно для цикличного слайдера — мы же на 1-м слайде, а листается «назад».&lt;/p&gt;
  &lt;p id=&quot;f295&quot;&gt;То есть, нам и здесь надо подставить условие с заменой, правда немного с другой проверкой:&lt;/p&gt;
  &lt;pre id=&quot;6tm1&quot; data-lang=&quot;javascript&quot;&gt;if (currentSlideIndex === lastSlideIndex) { // если точно последний
  nextSlideIndex = 0; // меняем на первый
  
  getItemsByIndex();
  itemsAnimation(instant);
  switchClasses();
  
  nextSlideIndex = i;
} // потом уже слайдим&lt;/pre&gt;
  &lt;p id=&quot;BNb9&quot;&gt;Далее решим со стилями точек, напомню, выглядят они вот так:&lt;/p&gt;
  &lt;figure id=&quot;INRr&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/3a/de/3adef89c-1746-404a-a9c8-17df114f1e12.png&quot; width=&quot;110&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;7KpB&quot;&gt;Текущая &lt;code&gt;.current&lt;/code&gt; — непрозрачная, а остальные полупрозрачные. Всё привязано к тому же вспомогательному классу, поэтому для «листания» точек немного расширим функцию &lt;code&gt;switchClasses()&lt;/code&gt;. При этом надо учесть, опять же, что слайдов на один больше чем точек:&lt;/p&gt;
  &lt;pre id=&quot;Hlka&quot; data-lang=&quot;javascript&quot;&gt;const switchClasses = () =&amp;gt; {
  /* ... Меняем классы итемам ... */
  
  if (currentSlideIndex === lastSlideIndex) {
    buttonsDots[0].classList.remove(&amp;quot;current&amp;quot;);
  } else {
    buttonsDots[currentSlideIndex].classList.remove(&amp;quot;current&amp;quot;);
  }  
  
  if (nextSlideIndex === lastSlideIndex) {
    buttonsDots[0].classList.add(&amp;quot;current&amp;quot;);
  } else {
    buttonsDots[nextSlideIndex].classList.add(&amp;quot;current&amp;quot;);
  }
}&lt;/pre&gt;
  &lt;p id=&quot;5s10&quot;&gt;Если у нас текущий/следующий слайд это последний, то бишь клон 1-го, то активной делаем 1-ю точку, в остальных случаях по номеру индекса.&lt;/p&gt;
  &lt;p id=&quot;rb0N&quot;&gt;В этом случае правда будет небольшой баг — при &lt;code&gt;current&lt;/code&gt; позиции слайдера на клоне и нажатии на закрашенную, но всё еще активную первую точку (так как &lt;code&gt;i&lt;/code&gt; в цикле будет 0, что отлично от &lt;code&gt;current&lt;/code&gt;) будет срабатывать кривая анимация.&lt;/p&gt;
  &lt;p id=&quot;f8hx&quot;&gt;В этом случае можно не мудрить и просто дизеблить кнопку по классу. Отключить нажатия по ней можно с помощью свойства &lt;code&gt;pointer-events: none&lt;/code&gt;.&lt;/p&gt;
  &lt;pre id=&quot;OpOM&quot; data-lang=&quot;css&quot;&gt;.slider-dots__control.current {  pointer-events: none; }&lt;/pre&gt;
  &lt;p id=&quot;nsZo&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;BuSm&quot;&gt;Смена стилей сайта&lt;/h3&gt;
  &lt;p id=&quot;3tAx&quot;&gt;Если не знать как работает каскад стилей, задача может показаться крайне сложной. Но мы-то с вами тёртые калачи, ёпты, и знаем, что для этой магии достаточно буквально нескольких строчек кода.&lt;/p&gt;
  &lt;p id=&quot;UK67&quot;&gt;У меня в стилях заранее заготовлены стили для трёх состояний тега &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt;:&lt;/p&gt;
  &lt;ol id=&quot;msQF&quot;&gt;
    &lt;li id=&quot;DW2c&quot;&gt;Без дополнительных классов стиль сайта розовый.&lt;/li&gt;
    &lt;li id=&quot;ioh7&quot;&gt;С классом &lt;code&gt;.page-body--blue&lt;/code&gt; оформление (фон, кнопочки, акценты) меняются на голубенький.&lt;/li&gt;
    &lt;li id=&quot;Ax0c&quot;&gt;С классом &lt;code&gt;.page-body--yellow&lt;/code&gt; на жёлтый.&lt;/li&gt;
  &lt;/ol&gt;
  &lt;p id=&quot;oCC3&quot;&gt;Нам осталось только воткнуть смену этих классов на &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt;, но с определёнными условиями. Нам нужно что бы оформление менялось одно за другим, то бишь надо как-то условно ограничить в зависимости от индексов.&lt;/p&gt;
  &lt;p id=&quot;aDdq&quot;&gt;Долго тут мусолить нечего — берём индексы слайдов и проверку на остатки, чтобы учесть теоретическое переполнение, получаем:&lt;/p&gt;
  &lt;pre id=&quot;WdnH&quot; data-lang=&quot;javascript&quot;&gt;if (nextSlideIndex === 0 || nextSlideIndex % lastSlideIndex === 0) {
  document.body.classList.remove(&amp;quot;page-body--blue&amp;quot;, &amp;quot;page-body--yellow&amp;quot;)
} else if (nextSlideIndex === 1 || nextSlideIndex % lastSlideIndex === 1) {
  document.body.classList.add(&amp;quot;page-body--blue&amp;quot;);
  document.body.classList.remove(&amp;quot;page-body--yellow&amp;quot;)
} else if (nextSlideIndex === 2 || nextSlideIndex % lastSlideIndex === 2) {
  document.body.classList.add(&amp;quot;page-body--yellow&amp;quot;)
  document.body.classList.remove(&amp;quot;page-body--blue&amp;quot;);
}&lt;/pre&gt;
  &lt;p id=&quot;tIv0&quot;&gt;Пихаем полученную красоту в ту же функцию &lt;code&gt;switchClasses()&lt;/code&gt; и получаем итоговый готовый слайдер. Теперь точно всё!&lt;/p&gt;
  &lt;p id=&quot;L9pT&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;VlXC&quot;&gt;Ссылки и финал&lt;/h2&gt;
  &lt;p id=&quot;z9zr&quot;&gt;Всем кто каким-то чудом дочитал или хотя бы до листал до этого момента огромное спасибо за внимание! У меня это все дело заняло целую неделю, но я даже не жалею. Было очень интересно разобраться самостоятельно.&lt;/p&gt;
  &lt;p id=&quot;Vcgu&quot;&gt;Во время работы я много чего находил, все ссылки со Stackoverflow и MDN я кидать не буду, но ключевые штуки которые мне помогли оставлю:&lt;/p&gt;
  &lt;ul id=&quot;cnPG&quot;&gt;
    &lt;li id=&quot;jTYK&quot;&gt;&lt;a href=&quot;https://stackoverflow.com/questions/15876754/infinity-loop-slider-concepts&quot; target=&quot;_blank&quot;&gt;Вопрос на Stackoverflow&lt;/a&gt; где написан концепт бесконечного слайдера на jQuery за счет клонирования первого и последнего итема.&lt;/li&gt;
    &lt;li id=&quot;RW89&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=wjC8iGt67UE&quot; target=&quot;_blank&quot;&gt;Вариант слайдера&lt;/a&gt; с заменой на &lt;code&gt;transitionend&lt;/code&gt;, косвенно помог — натолкнул на идею с индексами и помог разобраться с интерполяцией.&lt;/li&gt;
    &lt;li id=&quot;P5cX&quot;&gt;&lt;a href=&quot;https://dev.to/rajnishkatharotiya/pick-desired-key-value-pair-from-an-object-48aa&quot; target=&quot;_blank&quot;&gt;Хитрая фича&lt;/a&gt; с &lt;code&gt;.reduce()&lt;/code&gt; сломавшая мне мозг, но которая помогла мне решить вопрос с фильтрацией свойств.&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;R9g0&quot;&gt;И еще десятки статей с MDN, спецификаций и других ресурсов.&lt;/p&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;5att&quot; data-align=&quot;center&quot;&gt;&lt;a href=&quot;https://t.me/arkhelvetios&quot; target=&quot;_blank&quot;&gt;Telegram&lt;/a&gt; — &lt;a href=&quot;https://twitter.com/arkhelvetios&quot; target=&quot;_blank&quot;&gt;Twitter&lt;/a&gt; — &lt;a href=&quot;https://www.instagram.com/arkhelvetios/&quot; target=&quot;_blank&quot;&gt;Instagram&lt;/a&gt; — &lt;a href=&quot;https://vk.com/arkhelvetios&quot; target=&quot;_blank&quot;&gt;VK&lt;/a&gt;&lt;/p&gt;
  &lt;/section&gt;

</content></entry><entry><id>helvetios:html-academy-level-1</id><link rel="alternate" type="text/html" href="https://teletype.in/@helvetios/html-academy-level-1?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=helvetios"></link><title>Курс «HTML и CSS. Профессиональная вёрстка сайтов» – асинхронный формат</title><published>2022-10-10T21:06:31.076Z</published><updated>2022-10-10T21:06:31.076Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img2.teletype.in/files/d1/49/d149eca4-354e-4e0a-bd50-b12380f5887a.png"></media:thumbnail><category term="webdev" label="Веб-разработка"></category><summary type="html">&lt;img src=&quot;https://img2.teletype.in/files/1c/33/1c33759d-e691-4ec8-8d1e-e9f6de2fd0d7.png&quot;&gt;Всем привет. Я таки прошел все тренажёры HTML Academy, хоть и о последних блоках про JavaScript писать не стал — подписка кончилась, буквально, в последний день прохождения заданий, а оплачивать её только ради конспекта здесь не хотелось.</summary><content type="html">
  &lt;figure id=&quot;pFI0&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/1c/33/1c33759d-e691-4ec8-8d1e-e9f6de2fd0d7.png&quot; width=&quot;1200&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;VEZ7&quot;&gt;Всем привет. Я таки прошел все тренажёры HTML Academy, хоть и о последних блоках про JavaScript писать не стал — подписка кончилась, буквально, в последний день прохождения заданий, а оплачивать её только ради конспекта здесь не хотелось.&lt;/p&gt;
  &lt;p id=&quot;6TlO&quot;&gt;К тому же, тренажёры — это только начальный этап и темы в блоках посвященные JavaScript, будут еще не раз встречаться далее в обучении. Часть из них уже встретились в конце самого первого курса — «HTML и CSS. Профессиональная вёрстка сайтов».&lt;/p&gt;
  &lt;p id=&quot;ECtJ&quot;&gt;Я проходил этот курс в рамках профессии «Фронтенд-разработчик» в асинхронном или, если по простому, в самостоятельном формате. Сама «Профессия» — это, грубо говоря, пакет курсов, а самостоятельный формат — более дешёвый и гибкий по времени. Для меня такие условия звучали идеально, но на самом деле отличия от обычных курсов не только в этом.&lt;/p&gt;
  &lt;p id=&quot;Ukcs&quot;&gt;Этой статьёй я хочу резюмировать свое самостоятельное прохождение этого курса — что нового узнал, как справился с проектом, что понравилось, а что не очень. Можно назвать это отзывом.&lt;/p&gt;
  &lt;p id=&quot;oUJD&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;Y8Vt&quot;&gt;О чём курс?&lt;/h2&gt;
  &lt;p id=&quot;c0lc&quot;&gt;Решил, что важно немного пояснить, а то заголовок-то у курса кричащий, но не конкретизирующий. Курс, сюрприз — про вёрстку, но не про всю. Первый курс, который в Академии еще называется «Уровень 1», посвящён только статичной вёрстке, &lt;strong&gt;без адаптивности&lt;/strong&gt; под разные устройства.&lt;/p&gt;
  &lt;figure id=&quot;BIAl&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/3b/ff/3bffd431-e5c6-444d-8139-d2039d9cb01f.png&quot; width=&quot;540&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;rAWL&quot;&gt;В курсе есть разделы про флексбокс и грид, но ими мы пользуемся для построения сеток в рамках статичной ширины сайта. Основной фокус курса — научить всем навыкам вёрстки без усложнений в виде настройки окружения, оптимизаций, препроцессоров и т. д. &lt;/p&gt;
  &lt;p id=&quot;Ide1&quot;&gt;Я бы не сказал, что это плохо — это просто нюанс.&lt;/p&gt;
  &lt;p id=&quot;3c12&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;uEe0&quot;&gt;Программа обучения&lt;/h2&gt;
  &lt;p id=&quot;x1g3&quot;&gt;В процессе прохождения курса мы работаем над &lt;strong&gt;проектом&lt;/strong&gt; — выбираем из макетов какой понравится и начинаем его постепенно верстать проходя от раздела к разделу. Макеты разные по сложности, но всё показывают на относительно простом демо-макете «Барбершоп», который выбрать нельзя. &lt;/p&gt;
  &lt;figure id=&quot;NV0R&quot; class=&quot;m_column&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/13/ed/13ed4187-181e-42a0-bf85-81acd40d0417.png&quot; width=&quot;1065&quot; /&gt;
    &lt;figcaption&gt;Доступные проекты&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;knhQ&quot;&gt;То бишь, какие-то вещи в любом случае надо как-то решать самому и даже не по образу и подобию, а решать задачу имеющимися знаниями и средствами. Это на мой взгляд круто, хотя я и видел обратную реакцию, мол за деньги мне должны всё разжевать и в рот положить. Тут, наверное, кому как.&lt;/p&gt;
  &lt;p id=&quot;PTYY&quot;&gt;Выполнять проект нужно в соответствии с &lt;strong&gt;техническим заданием&lt;/strong&gt; — там есть прям неочевидные нюансы, и еще в соответствии с &lt;strong&gt;критериями&lt;/strong&gt; — достаточно большим списком требований к итоговой работе. Например, переполнение — чтобы сайт не разваливался при любом количестве контента в любом отдельно взятом блоке.&lt;/p&gt;
  &lt;p id=&quot;pbCw&quot;&gt;Курс поделён на 10 разделов, а каждый раздел поделён еще на, назовём это, стадии:&lt;/p&gt;
  &lt;ol id=&quot;5gZD&quot;&gt;
    &lt;li id=&quot;MvKl&quot;&gt;&lt;strong&gt;Подготовка к вебинару&lt;/strong&gt;, которая часто разделена еще на:&lt;/li&gt;
    &lt;ol id=&quot;tKje&quot;&gt;
      &lt;li id=&quot;TrcH&quot;&gt;&lt;strong&gt;Тренажёры&lt;/strong&gt; (да, они здесь как часть обучения).&lt;/li&gt;
      &lt;li id=&quot;oRgz&quot;&gt;&lt;strong&gt;Статьи&lt;/strong&gt; из «Учебника» или какие-то внешние статьи по теме раздела.&lt;/li&gt;
    &lt;/ol&gt;
    &lt;li id=&quot;Qwau&quot;&gt;&lt;strong&gt;Лайв&lt;/strong&gt; или вебинар (точнее запись), на котором разбираются интерактивные «Демки» и авторы курса комментируют подходы к задаче. Это именно не лекции, а разбор задачи и «узких мест» в реализации.&lt;/li&gt;
    &lt;li id=&quot;lBEk&quot;&gt;Сами «&lt;strong&gt;Демки&lt;/strong&gt;» — это как тренажёры, но там всё уже решено и каждый шаг идёт с пояснениями.&lt;/li&gt;
    &lt;li id=&quot;OUlH&quot;&gt;&lt;strong&gt;Домашнее задание&lt;/strong&gt; — это страницы c описанием чего делать в рамках раздела со своим проектом. Так как формат самостоятельный и наставника нет, есть ещё разбор примера, но только на один лёгкий проект (Nёrds).&lt;/li&gt;
    &lt;li id=&quot;ZT2X&quot;&gt;&lt;strong&gt;Дополнительные материалы&lt;/strong&gt; — в них частенько много полезной инфы, но есть и прям филлеры, особенно в одном разделе (позже напишу).&lt;/li&gt;
  &lt;/ol&gt;
  &lt;figure id=&quot;urRQ&quot; class=&quot;m_column&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/fd/a5/fda529a0-1812-4867-9e0d-51c631bf91cf.png&quot; width=&quot;1048&quot; /&gt;
    &lt;figcaption&gt;Пример структуры внутри раздела&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;ycYo&quot;&gt;Сами разделы описывать не буду, они &lt;a href=&quot;https://htmlacademy.ru/intensive/htmlcss#program&quot; target=&quot;_blank&quot;&gt;вот тут&lt;/a&gt; на сайте самого курса есть, там без сюрпризов — разметка, сетки, декорации, доступность, мать её, и щепоть JavaScript для модальных окон. Хотя, сейчас написал про модалки и вспомнил, что всё же есть нюансы.&lt;/p&gt;
  &lt;p id=&quot;Ublp&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;c5Ln&quot;&gt;Отличие асинхронного формата&lt;/h2&gt;
  &lt;p id=&quot;pOnp&quot;&gt;Главное отличие — это, естественно, цена. Но тут сложно посчитать, так как я оплачивал сразу профессию, не уверен, есть ли отдельно сольный курс. В любом случае, надо понимать, что за более дешёвый вариант курса, полагается менее приоритетный сервис.&lt;/p&gt;
  &lt;p id=&quot;Mqu3&quot;&gt;Во-первых, &lt;strong&gt;у нас нет наставников&lt;/strong&gt;. Их место занимает Discord-сервер для оплативших профессию, где участники могут задавать вопросы и дежурные наставники отвечают на них. Иногда. &lt;/p&gt;
  &lt;p id=&quot;vgep&quot;&gt;Ладно, справедливости ради, они правда вроде как стараются отвечать, но так как это явно не их основная работа, есть риск, что вопрос просто проигнорится если его лишний раз не пингануть. &lt;/p&gt;
  &lt;p id=&quot;bj0C&quot;&gt;Очень часто отвечают более опытные ученики, что радует:&lt;/p&gt;
  &lt;figure id=&quot;FIdt&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/b2/35/b235b7d9-68b1-4f53-bf89-8d2bfb327f1b.png&quot; width=&quot;1087&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;rgTO&quot;&gt;Наставника, кстати, всего два не просто на курс, а сразу на всю «Профессию», а это, на минуточку, 5 курсов. Народу, конечно, на момент сентября вроде как немного (я не вижу всех кто офлайн), вопросы задаются с переменной частотой, иногда несколько суток ни одного. Поэтому, сажать на дежурство десяток наставников, наверное, нецелесообразно.&lt;/p&gt;
  &lt;p id=&quot;Axi6&quot;&gt;Второе отличие — &lt;strong&gt;количество проектов&lt;/strong&gt;. В полном курсе их, не считая «Барбершопа», пять штук. В порядке возрастания сложности:&lt;/p&gt;
  &lt;ol id=&quot;kMWW&quot;&gt;
    &lt;li id=&quot;Btlj&quot;&gt;Nёrds&lt;/li&gt;
    &lt;li id=&quot;81qs&quot;&gt;Sedona&lt;/li&gt;
    &lt;li id=&quot;FWjZ&quot;&gt;Техномарт&lt;/li&gt;
    &lt;li id=&quot;OIk5&quot;&gt;Device&lt;/li&gt;
    &lt;li id=&quot;7oPA&quot;&gt;Gllacy&lt;/li&gt;
  &lt;/ol&gt;
  &lt;p id=&quot;xIgz&quot;&gt;Как видно по скрину выше — в асинхронном формате доступны только первые три, то есть, самые сложные проекты Device и Gllacy не доступны. Я еще когда смотрел сайт курса хотел взять Device, а тут слегка обломилось. В итоге я взял Техномарт, но это не конец истории, об этом чуть позже.&lt;/p&gt;
  &lt;p id=&quot;ckGF&quot;&gt;Третье отличие — &lt;strong&gt;нет обязательного взаимодействия с GitHub&lt;/strong&gt;. Это, на самом деле, вредное отличие, так как уже в «Уровне 2» начинается прям полное погружение в Git и уж лучше сразу хотя бы базово с ним разобраться, хотя бы на уровне как сделать эти ваши пуши, коммиты, пул-реквесты и т. д.&lt;/p&gt;
  &lt;p id=&quot;JU2i&quot;&gt;Четвёртое отличие — &lt;strong&gt;нет защиты проекта&lt;/strong&gt;. Это скорее касается всей профессии, так как есть только итоговое грейдирование по итогу всего пройденного материала. Что это такое не очень понятно, видимо что-то вроде экзамена по всем курсам, но отдельных защит или экзаменов по каждому курсу нет.&lt;/p&gt;
  &lt;p id=&quot;Trqh&quot;&gt;Пятое отличие — не дадут сертификат и ачивку в личном кабинете. &lt;code&gt;:(&lt;/code&gt;&lt;/p&gt;
  &lt;figure id=&quot;YAF6&quot; class=&quot;m_original&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/bb/35/bb358dca-d24a-4a78-ad7f-aef2dbe2a53f.png&quot; width=&quot;272&quot; /&gt;
    &lt;figcaption&gt;Успешно прошел, а шарик не дали, в классе заперли.&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;Ljmj&quot;&gt;Еще одно такое, мини-отличие, которое заметил в последнем разделе по JS — не разбираются слайдеры, только модальные окна. Увидел в разборе домашнего задания, что у ученика полного курса слайдеры есть. Ну и ладно.&lt;/p&gt;
  &lt;p id=&quot;lGfQ&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;3HNk&quot;&gt;Чему научился?&lt;/h2&gt;
  &lt;p id=&quot;FUYe&quot;&gt;Очень многое в курсе построено на тренажёрах, а так как я их уже прошел, то и значительную часть я уже знал. Плюс тот самый «&lt;a href=&quot;https://blog.arkhelvetios.ru/keksby&quot; target=&quot;_blank&quot;&gt;Великий Кексби&lt;/a&gt;» подготовил меня к подобному формату самостоятельной работы.&lt;/p&gt;
  &lt;p id=&quot;1HXO&quot;&gt;Однако, в учебнике все-таки были некоторые особо важные темы. Самые массивные из них — методики. Их несколько в разных разделах, например, методика построения семантически верной разметки, методика БЭМ, методика построения сеток и микросеток, методика работы с отступами и другие.&lt;/p&gt;
  &lt;p id=&quot;X2mi&quot;&gt;Это такие огромные, подробные мануалы с пошаговым разбором действий, типовых ошибок, «бестпрактиз», хинтов и так далее — пожалуй, одни из наиболее полезных штук в курсе.&lt;/p&gt;
  &lt;p id=&quot;BmTk&quot;&gt;Например, в ходе первых разделов, наконец стало точно понятно в чем отличие &lt;code&gt;&amp;lt;section&amp;gt;&lt;/code&gt; и &lt;code&gt;&amp;lt;article&amp;gt;&lt;/code&gt;. Почему обязательно нужны &lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt; для &lt;code&gt;&amp;lt;section&amp;gt;&lt;/code&gt; даже если их нет на макете. Где разумно &lt;code&gt;&amp;lt;section&amp;gt;&lt;/code&gt;, а где лучше &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt;.&lt;/p&gt;
  &lt;figure id=&quot;pUrB&quot; class=&quot;m_column&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/da/b8/dab8d817-cba3-4552-a90a-c1a2d65b1942.png&quot; width=&quot;707&quot; /&gt;
    &lt;figcaption&gt;Выглядит аж красиво. Или я схожу с ума?&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;3M4l&quot;&gt;Про БЭМ это вообще отдельный разговор, мир не станет прежним — я всё думал, что за &lt;code&gt;__&lt;/code&gt; везде в классах на сайтах, а оно вон чего. Хотя БЭМ в курсе и не требуют, но я сразу начал практиковаться.&lt;/p&gt;
  &lt;p id=&quot;F7Ei&quot;&gt;Научился подключать favicon и webmanifest — ничего сложного, но с нюансами. Сама favicon оказывается работает даже если её тупо шваркнуть в корневую папку, но лучше всё-таки явно прописать.&lt;/p&gt;
  &lt;p id=&quot;2rrf&quot;&gt;Много узнал и изучил про normalize.css и его прародителей. &lt;/p&gt;
  &lt;p id=&quot;zTKW&quot;&gt;Научился грамотно подключать шрифты в CSS через &lt;code&gt;@font-face&lt;/code&gt;. В дополнительных материалах есть записи с каких-то выступлений Вадима Макеева, он там очень много интересных штук про это рассказывает.&lt;/p&gt;
  &lt;p id=&quot;l9hL&quot;&gt;Отдельным открытием были кастомные свойства. Это по сути как переменные, но в чистом CSS. Я сначала даже не поверил. Серьезно? А нафига тогда препроцессоры? Видимо, для миксинов. &lt;/p&gt;
  &lt;figure id=&quot;tMuC&quot; class=&quot;m_original&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/2e/b6/2eb6e9ae-50be-45e4-9793-7ca13b17e2c7.png&quot; width=&quot;621&quot; /&gt;
    &lt;figcaption&gt;Тут только цвета, но вообще можно почти любые значения&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;zBQL&quot;&gt;Сетки прошли практически без сюрпризов, уж их-то я еще на тренажёрах изучил наперёд. Уверен, что еще споткнусь на нюансах на 2-м уровне, но пока мне хватило опыта — были одни из самых комфортных разделов.&lt;/p&gt;
  &lt;p id=&quot;77CT&quot;&gt;Единственный неизвестный мне хинт который я, внезапно, услышал от наставника в разборе домашнего задания — про расчёт ширины в гриде. &lt;/p&gt;
  &lt;pre id=&quot;Lf0O&quot; data-lang=&quot;css&quot;&gt;grid-template-columns: 1fr 2fr;
//не равно
grid-template-columns: repeat(3, 1fr);&lt;/pre&gt;
  &lt;p id=&quot;LO3n&quot;&gt;Вы, возможно, смотрите и такие «Ты чо дурак?». Нюанс приобретает смысл, когда у вас структура колонок 1 к 2 или 1 к 3, в общем дробная, там где так и хочется использовать в лоб &lt;code&gt;fr&lt;/code&gt;. &lt;/p&gt;
  &lt;figure id=&quot;BFXC&quot; class=&quot;m_column&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/95/40/95406984-0392-416e-b56e-034065ff6aee.png&quot; width=&quot;957&quot; /&gt;
    &lt;figcaption&gt;Типа как тут – хочется сделать 1fr 3fr&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;NOSk&quot;&gt;Однако, надо еще не забывать про &lt;code&gt;gap&lt;/code&gt; и что он, по сути, тоже учувствует в расчёте ширины. А от того как вы зададите &lt;code&gt;grid-template-columns&lt;/code&gt; будет отличаться количество ячеек, а как следствие гэпов и в конечном итоге размер доли под которую выделен контент.&lt;/p&gt;
  &lt;p id=&quot;3UYx&quot;&gt;Много разных нюансов по поводу интерактивных объектов и их плохой наследуемости свойств. В Техномарте есть форма из одного поля поиска в хэдере, вот с ней прям засел я на пару часиков.&lt;/p&gt;
  &lt;figure id=&quot;CuqI&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/67/3e/673eccd6-7762-48de-9b80-4146a69af995.gif&quot; width=&quot;480&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;a5j9&quot;&gt;Остальные декорации заняли много времени, но в основном в тренажёрах уже разбирались. Немного, правда, провозился на чекбоксах и радио — хотел сделать их не через SVG-иконки, а методами CSS, но споткнулся о галочку в чекбоксе — у нее была обводка закрывающая часть контура.&lt;/p&gt;
  &lt;figure id=&quot;Ycgx&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/06/5f/065fa54d-2d81-4191-b922-74f4fcde7c1a.png&quot; width=&quot;182&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;nREg&quot;&gt;Узнал про переполнение и как его предвидеть. Немного даже перестарался, по-моему — учел даже переполнение в одну строку без пробелов в местах, где текст явно не абзац осмысленного текста, а короткое описание (типа &lt;code&gt;&amp;lt;label&amp;gt;&lt;/code&gt;).&lt;/p&gt;
  &lt;p id=&quot;y0Vw&quot;&gt;Базово разобрался с минификаторами CSS и JS, правда, насколько понял из Лайва, что есть технология, которая всё это дело автоматизирует и мы её разберём на 2-м уровне.&lt;/p&gt;
  &lt;p id=&quot;A3E4&quot;&gt;Наконец, самый мутный раздел — доступность. Это тот раздел, где в дополнительных материалах целая плеяда о-очень нудных филлерных статей на эту тему. Столько свой TAB я еще не насиловал. Со скринридером проблем, внезапно, не оказалось. А вот с отображением фокуса на моих кастомных чекбоксах — да. Пришлось допиливать.&lt;/p&gt;
  &lt;p id=&quot;sj6M&quot;&gt;В разделе про JS мы искали элементы через &lt;code&gt;.querySelector()&lt;/code&gt;, игрались с классами через &lt;code&gt;.classList&lt;/code&gt; и немного разобрались с работой &lt;code&gt;localStorage&lt;/code&gt;. Запрограммировали открытие и закрытие модалок и еще настроили автофокус при открытии и автозаполнение полей по ключу из &lt;code&gt;localStorage&lt;/code&gt;.&lt;/p&gt;
  &lt;p id=&quot;cOJJ&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;ZaOk&quot;&gt;Про проекты&lt;/h2&gt;
  &lt;p id=&quot;aSxt&quot;&gt;Я сначала пытался затрайхардить и делать параллельно все три доступных проекта. И, в общем-то, до 4го раздела так и было — вся разметка и часть стилизации у меня готово и для Техномарта и для Nёrds с Седоной.&lt;/p&gt;
  &lt;p id=&quot;umCk&quot;&gt;В определённый момент я даже начал искать по интернету остальные два проекта и даже нашёл. Труда особого не составило — они не то чтобы прям в общем доступе, но и не за семью печатями. GitHub и Google вам в помощь.&lt;/p&gt;
  &lt;figure id=&quot;fMLL&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/63/34/6334d3b7-c811-47ff-81d5-d5f84d9b2ee1.png&quot; width=&quot;1109&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;UKuQ&quot;&gt;И в какой-то момент моя душонка такая — «А давай сделаем их все!». Где-то как раз в этот момент мне надо было улетать в другой город на несколько дней по делам и… слава богам, я рад что мне это помешало.&lt;/p&gt;
  &lt;p id=&quot;7q6o&quot;&gt;Дело не в лени или в том, что это какой-то перебор в практике. Дело в том, что лучше реально сделать один проект до конца.&lt;/p&gt;
  &lt;p id=&quot;0Fxv&quot;&gt;Работая над Техномартом я несколько раз тупо переписывал огромные куски как и вёрстки так и стилей, так как повествование в курсе идёт иногда в виде «Оставим пока так — потом поправим/доделаем». А теперь умножьте это на 5, а то и на 10, так как Девайс и Глейси судя по макетам сильно сложнее Техномарта и тем более Nёrds или Седоны.&lt;/p&gt;
  &lt;p id=&quot;M61W&quot;&gt;В идеале — я бы взял Глейси, как, на мой взгляд, самый сложный макет и работал бы с ним в процессе обучения. Сразу разобраться со всеми сложностями и пусть это займет больше времени, но, я уверен, даст фору позже.&lt;/p&gt;
  &lt;p id=&quot;c9Cx&quot;&gt;И уже если потом появилось желание закрепить или тупо закрыть свои гештальты (как у меня) можно приступать к остальным проектам. Опять же если вы в асинхронном формате, а в обычном, насколько я понимаю, особо не по растекаешься на проекты, т. к. там времечко жмёт.&lt;/p&gt;
  &lt;p id=&quot;NfSV&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;Gis2&quot;&gt;Сколько времени заняло&lt;/h2&gt;
  &lt;p id=&quot;vNwL&quot;&gt;Моя любимая часть. Я не так давно занялся этим вот подсчётом личной эффективности, график, таймеры и т. д. Напишу как получилось. Для всего этого дела использовал приложение Toggl Track — оно бесплатное, крайне рекомендую.&lt;/p&gt;
  &lt;p id=&quot;VbUk&quot;&gt;Всё обучение заняло у меня 29 дней — чуть более 4-х недель. Это, правда, с учетом, что мне на 5 дней пришлось улететь в другой город по делам. &lt;/p&gt;
  &lt;p id=&quot;8Czn&quot;&gt;Я не трайхардил до посинения, как делал это на тренажёрах весной, в среднем старался держаться около 20 часов в неделю. Так, в общем-то, и получилось, если учесть пятидневный перерыв.&lt;/p&gt;
  &lt;p id=&quot;sD0V&quot;&gt;В сумме первый курс «HTML и CSS. Профессиональная вёрстка сайтов» занял у меня 68 часов чистых обучения:&lt;/p&gt;
  &lt;figure id=&quot;2BE7&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/a8/68/a868edb8-3905-4662-bc6f-91933e748194.png&quot; width=&quot;738&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;I3fY&quot;&gt;В таймер включены мои повторные прохождения тренажёров — тут, понятное дело, не очень объективно, так как я их пролетал зная чего делать. Так что можно смело еще плюсовать ~8 часов, наверное.&lt;/p&gt;
  &lt;p id=&quot;IgJP&quot;&gt;С другой стороны, я нарочно НЕ учитывал просмотры Лайвов, которые в среднем 1.5-2 часа каждый, хотя я и смотрел их на х2. Они просто, по сути, идут по Демкам, которые я сам пролистывал многократно в ходе работы над заданием и вот это я уже учитывал в таймер.&lt;/p&gt;
  &lt;p id=&quot;pRqG&quot;&gt;&lt;/p&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;gxHn&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;mBCf&quot;&gt;Сейчас я уже приступил к следующему курсу «&lt;a href=&quot;https://htmlacademy.ru/intensive/adaptive&quot; target=&quot;_blank&quot;&gt;HTML и CSS. Адаптивная вёрстка и автоматизация&lt;/a&gt;» или «Уровень 2» и это немного не то, что я ожидал. В хорошем ключе. Я еще удивлялся — почему адаптивность отрезали от вёрстки, ведь это в современном мире мастхэв. Оказалось не всё так просто и с адаптивом на 2-м уровне идёт еще пачка технологий и адаптив как таковой не ограничивается шириной экрана или «резиновостью».&lt;/p&gt;
  &lt;p id=&quot;FIfA&quot;&gt;За сим всё, спасибо за внимание! Продолжу в том же духе и встретимся уже после следующего курса.&lt;/p&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;FDSz&quot; data-align=&quot;center&quot;&gt;&lt;a href=&quot;https://t.me/arkhelvetios&quot; target=&quot;_blank&quot;&gt;Telegram&lt;/a&gt; — &lt;a href=&quot;https://twitter.com/arkhelvetios&quot; target=&quot;_blank&quot;&gt;Twitter&lt;/a&gt; — &lt;a href=&quot;https://www.instagram.com/arkhelvetios/&quot; target=&quot;_blank&quot;&gt;Instagram&lt;/a&gt; — &lt;a href=&quot;https://vk.com/arkhelvetios&quot; target=&quot;_blank&quot;&gt;VK&lt;/a&gt;&lt;/p&gt;
  &lt;/section&gt;

</content></entry><entry><id>helvetios:muesli-1-skills-or-theory</id><link rel="alternate" type="text/html" href="https://teletype.in/@helvetios/muesli-1-skills-or-theory?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=helvetios"></link><title>Прикладные навыки или глубокая теория?</title><published>2022-08-18T16:05:07.420Z</published><updated>2022-08-18T16:05:07.420Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img1.teletype.in/files/0c/59/0c59cf90-687b-4541-810d-2a2513ebe045.png"></media:thumbnail><category term="myusli" label="Мюсли в голове"></category><summary type="html">&lt;img src=&quot;https://img1.teletype.in/files/83/45/8345b0f8-bfc5-4e98-9d8f-b64c5567236c.png&quot;&gt;У меня всегда был на эту тему диссонанс. С одной стороны — я люблю докапываться до фундаментальной основы всего, что мне интересно. Это проявляется и в быту, и в хобби, и в работе. </summary><content type="html">
  &lt;figure id=&quot;sDCE&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/83/45/8345b0f8-bfc5-4e98-9d8f-b64c5567236c.png&quot; width=&quot;1200&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;gR5f&quot;&gt;У меня всегда был на эту тему диссонанс. С одной стороны — я люблю докапываться до фундаментальной основы всего, что мне интересно. Это проявляется и в быту, и в хобби, и в работе. &lt;/p&gt;
  &lt;p id=&quot;XbQt&quot;&gt;Из бытового — когда я впервые делал ремонт, не так давно, кстати, я решил не клеить обои, а просто покрасить стены. В процессе изучения вопроса узнал, что перед покраской обязательно нужна некая «Грунтовка», а через пару часов уже изучаю адгезию, когезию, вспоминаю термодинамику, 2-й курс универа и господина Ван-дер-Ваальса.&lt;/p&gt;
  &lt;p id=&quot;cquA&quot;&gt;С физикой у меня вообще полюбовные отношения, не смотря на то, что в универе я не особо отличился каким-то успехом в учёбе. Например, мне безумно нравится смотреть научпоп вообще на любые математические, физические и химические темы. Обнаружить себя в 4 утра с 30+ открытыми вкладками Википедии и лекций — для меня норма. В особо интенсивных случаях достается тетрадь и ручка, скачивается дедушка Mathcad или Labview.&lt;/p&gt;
  &lt;p id=&quot;T1nz&quot;&gt;Отдельный, можно сказать, вид «научпопного искусства» это визуализации квантово-механических процессов и, пользуясь случаем, порекомендую несколько крышесносных видео на эту тему:&lt;/p&gt;
  &lt;ul id=&quot;abcJ&quot;&gt;
    &lt;li id=&quot;QIi4&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=YiuZUDYSPs8&quot; target=&quot;_blank&quot;&gt;Общая теория относительности&lt;/a&gt; и &lt;a href=&quot;https://www.youtube.com/watch?v=3uGQHlmyfVw&quot; target=&quot;_blank&quot;&gt;её визуализация&lt;/a&gt;;&lt;/li&gt;
    &lt;li id=&quot;0Ftb&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=9sv-RElTc6s&quot; target=&quot;_blank&quot;&gt;Квантовая теория поля&lt;/a&gt;;&lt;/li&gt;
    &lt;li id=&quot;Q98h&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=w3jpKJSrV_k&quot; target=&quot;_blank&quot;&gt;Теория струн&lt;/a&gt;;&lt;/li&gt;
    &lt;li id=&quot;bdhL&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=JoDmsVNzT8A&quot; target=&quot;_blank&quot;&gt;Прыжок в чёрную дыру теория&lt;/a&gt; и безумно крутой &lt;a href=&quot;https://www.youtube.com/watch?v=17tEg_uTF_A&quot; target=&quot;_blank&quot;&gt;POV 360&lt;/a&gt;;&lt;/li&gt;
    &lt;li id=&quot;d0pp&quot;&gt;Там много всего — &lt;a href=&quot;https://www.youtube.com/playlist?list=PL0_0CkR5Zh9vZSH1EifLyESonPwqVmYgZ&quot; target=&quot;_blank&quot;&gt;перевод на русский&lt;/a&gt;, &lt;a href=&quot;https://www.youtube.com/playlist?list=PLu7cY2CPiRjVCbSWwSe0mXxWK0S8e8Ssx&quot; target=&quot;_blank&quot;&gt;оригинал на английском&lt;/a&gt;.&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;8VUO&quot;&gt;В работе и учебе, в профессиональном плане, тоже частенько проявляется эта моя сторона. Из относительно недавнего — Кривые Безье. Я полез разбираться в математическое построение разных кривых с разным количеством опорных точек. Классические, если можно так сказать, Кривые Безье в графике — кубические в двумерном пространстве. Зачем вам эта информация? А мне она была зачем? Но я потратил на это часов 7-8 точно.&lt;/p&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;mPGZ&quot;&gt;С другой стороны — практической пользы от такого дотошного вникания во всё чаще всего нет или она околонулевая. Можно потратить сутки на что-то интересное, но крайне бесполезное. &lt;/p&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;JHgG&quot;&gt;Вопрос которым я озадачил себя — «Так уж ли важно наличие этой пользы»?&lt;/p&gt;
  &lt;/section&gt;
  &lt;p id=&quot;qX38&quot;&gt;Когда я начал изучать фронтэнд и программирование, я начал периодически слушать умных и опытных дядек-синьоров. Один из таких, кстати, господин Сергей Немчинский — классный дядька, его канал понравился. &lt;/p&gt;
  &lt;p id=&quot;ygVu&quot;&gt;Так вот, этими дядьками очень часто (скорее, даже — всегда) подаётся идея, что главное освоить востребованный навык или, как сейчас модно, «хардскилл», а остальное прилипнет по мере практики. И с таким тяжело спорить, так как программирование во многом прикладное искусство — практика здесь буквально основа мастерства.&lt;/p&gt;
  &lt;p id=&quot;w0ny&quot;&gt;То есть, если коротко — учишь основы, учишь фреймворк, ищешь трейни/джун оффер. Остальное отбрасывай, не трать время. Глубокая теория не нужна, потому что бизнес диктует дедлайны, а ПиЭм выставляет эстимейты в графике. &lt;/p&gt;
  &lt;p id=&quot;EGJj&quot;&gt;И тут как бы тоже хрен поспоришь.&lt;/p&gt;
  &lt;p id=&quot;PsL7&quot;&gt;И я сначала не спорил, но намедни пришло осознание, что это просто не мой случай. По крайней мере на данный момент. Меня не интересует работа в офисе, пусть даже за тысячи баксов в месяц, меня не интересуют офферы как таковые. Меня не интересует релокация, по крайней мере не в том положении и не по тем причинам по которым это делают сейчас люди.&lt;/p&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;RNG0&quot;&gt;Это помогло мне избавиться от странного груза, который висел на душе — мне просто хочется тратить, мать его, время на то что мне интересно, а не на то по каким правилам, якобы, работает индустрия (хотя на самом деле только часть).&lt;/p&gt;
  &lt;p id=&quot;OJxk&quot;&gt;Это же помогло ответить и на вопрос выше. Для меня польза не измеряется количеством фреймворков и технологий или зарплате, которую я получу. То есть она не прямо пропорциональна материальному благу или его подобию.&lt;/p&gt;
  &lt;p id=&quot;5q3P&quot;&gt;Моя «польза» — приятное ощущения от познания и понимания какой угодно и никакому бизнесу ненужной глубокой теории. Пусть даже в 4 утра.&lt;/p&gt;

</content></entry><entry><id>helvetios:less-academy</id><link rel="alternate" type="text/html" href="https://teletype.in/@helvetios/less-academy?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=helvetios"></link><title>Препроцессор Less — Тренажёр HTML Academy</title><published>2022-07-04T14:35:15.599Z</published><updated>2022-10-10T19:14:20.788Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img4.teletype.in/files/b6/72/b67259bb-f205-4baf-b1b5-3e0e9e55939a.png"></media:thumbnail><category term="webdev" label="Веб-разработка"></category><tt:hashtag>css</tt:hashtag><tt:hashtag>css3</tt:hashtag><tt:hashtag>less</tt:hashtag><tt:hashtag>frontend</tt:hashtag><tt:hashtag>front_end</tt:hashtag><tt:hashtag>обучение</tt:hashtag><tt:hashtag>it</tt:hashtag><summary type="html">&lt;img src=&quot;https://img3.teletype.in/files/e1/04/e104ae23-a57b-477f-933b-98cea36d1133.png&quot;&gt;Разобравшись с вёрсткой переходим к инструментам её ускорения. Мы уже знаем базовые вещи PHP, который формально препроцессор HTML, теперь же займемся CSS и одним из его препроцессоров Less.</summary><content type="html">
  &lt;figure id=&quot;ayvQ&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/e1/04/e104ae23-a57b-477f-933b-98cea36d1133.png&quot; width=&quot;1200&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;CJUp&quot;&gt;Разобравшись с вёрсткой переходим к инструментам её ускорения. Мы уже знаем базовые вещи PHP, который формально препроцессор HTML, теперь же займемся CSS и одним из его препроцессоров Less.&lt;/p&gt;
  &lt;p id=&quot;nQ2f&quot;&gt;Я, кстати, уже писал немножечко про один другой препроцессор CSS — в статье про &lt;a href=&quot;https://blog.arkhelvetios.ru/webref-mob#R08H&quot; target=&quot;_blank&quot;&gt;мобильное приложение&lt;/a&gt; для самообучение Webref, там нас познакомили с Sass и его упрощённым вариантом SCSS. Спойлер — отличия от Less всё-таки есть, особенно в синтаксисе, хотя по сути мало что меняется.&lt;/p&gt;
  &lt;p id=&quot;wW6q&quot;&gt;&lt;/p&gt;
  &lt;nav&gt;
    &lt;ul&gt;
      &lt;li class=&quot;m_level_1&quot;&gt;&lt;a href=&quot;#I5PR&quot;&gt;О препроцессорах&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_1&quot;&gt;&lt;a href=&quot;#u9om&quot;&gt;Возможности Less&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_2&quot;&gt;&lt;a href=&quot;#5G4Y&quot;&gt;Переменные&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_2&quot;&gt;&lt;a href=&quot;#Z6d6&quot;&gt;Математические операции&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_2&quot;&gt;&lt;a href=&quot;#ZDd3&quot;&gt;Цветовые функции&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_2&quot;&gt;&lt;a href=&quot;#QJRd&quot;&gt;Вложенные правила&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_1&quot;&gt;&lt;a href=&quot;#bF7F&quot;&gt;Примеси Less&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_2&quot;&gt;&lt;a href=&quot;#xUT3&quot;&gt;Шаблон примеси&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_2&quot;&gt;&lt;a href=&quot;#JjQQ&quot;&gt;Примесь с условием&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_2&quot;&gt;&lt;a href=&quot;#oh3y&quot;&gt;Вставки&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_2&quot;&gt;&lt;a href=&quot;#tl70&quot;&gt;Циклы&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_1&quot;&gt;&lt;a href=&quot;#0aoH&quot;&gt;Испытания&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/nav&gt;
  &lt;p id=&quot;9Z1Z&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;I5PR&quot;&gt;О препроцессорах&lt;/h2&gt;
  &lt;p id=&quot;6nUY&quot;&gt;Препроцессор позволяет подойти к языку разметки или стилей как к языку программирования — с переменными, условиями, циклами и так далее. Это касается и PHP для HTML, который &lt;a href=&quot;https://blog.arkhelvetios.ru/intro-php&quot; target=&quot;_blank&quot;&gt;мы разбирали&lt;/a&gt; уже достаточно давно, и это же касается Less или других вариантов для CSS.&lt;/p&gt;
  &lt;p id=&quot;CWHR&quot;&gt;Почему эти языки называются &lt;u&gt;пре&lt;/u&gt;процессорными, я уже &lt;a href=&quot;https://blog.arkhelvetios.ru/intro-to-web-development#6bxB&quot; target=&quot;_blank&quot;&gt;как-то давно писал&lt;/a&gt; в самом начале про PHP, но если вкратце — это языки которые обрабатывает сервер и трансформирует его в понятный для браузера HTML и CSS.&lt;/p&gt;
  &lt;p id=&quot;utrI&quot;&gt;В случае с Less мы по сути «программируем» стили, уменьшаем количество повторов и, тем самым, упрощаем себе работу. Меньше повторов, меньше времени на написание, больше логики и наглядности. Хотя по началу может показаться с точностью да наоборот.&lt;/p&gt;
  &lt;p id=&quot;ZV8M&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;u9om&quot;&gt;Возможности Less&lt;/h2&gt;
  &lt;p id=&quot;35A5&quot;&gt;Итак, теперь мы не только описываем стили элементов, но и пытаемся построить логику этого описания. Синтаксис самой основы CSS не меняется — все правила, свойства и их значения, что мы разбирали до этого, остаются такими же. Less же, можно сказать, надстройка в виде дополнительных функций.&lt;/p&gt;
  &lt;p id=&quot;45IA&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;5G4Y&quot;&gt;Переменные&lt;/h3&gt;
  &lt;p id=&quot;eWgi&quot;&gt;Первое, что можно сделать в Less — это &lt;strong&gt;объявить переменную&lt;/strong&gt;:&lt;/p&gt;
  &lt;pre id=&quot;tjWp&quot; data-lang=&quot;less&quot;&gt;@main-color: red;
@cintainer-width: 150px;&lt;/pre&gt;
  &lt;p id=&quot;UfoB&quot;&gt;Один раз объявив переменную, мы можем использовать её в любом месте кода, при этом, поменяв значение переменной — оно поменяется везде. Таким образом, сильно упрощается работа с большим объемом одинаковых параметров.&lt;/p&gt;
  &lt;pre id=&quot;MJAW&quot; data-lang=&quot;less&quot;&gt;.card-container {
  background-color: @main-color;
  width: @container-width; 
}

.description {
  color: @main-color;
}&lt;/pre&gt;
  &lt;p id=&quot;rI5g&quot;&gt;Переменные можно объявлять даже внутри правил, таким образом они становятся локальными для этого правила и работают только внутри него, то есть использовать эту переменную в другом правиле не получится. &lt;/p&gt;
  &lt;p id=&quot;V8sP&quot;&gt;С переменными Less работают стандартные &lt;strong&gt;правила области видимости&lt;/strong&gt; — переменные объявленные вне правил являются глобальными и могут применятся везде, при этом они могут переопределяться на локальные значение:&lt;/p&gt;
  &lt;pre id=&quot;qt8f&quot; data-lang=&quot;less&quot;&gt;.card-container {
  @container-width: 100px;
  
  background-color: @main-color; /* будет red -глобальное значение */
  width: @container-width; /* будет 100px - локальное значение */
}

.description {
  @main-color: blue;
  
  color: @main-color; /* будет blue - локальное значение */
}&lt;/pre&gt;
  &lt;p id=&quot;EZ8C&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;Z6d6&quot;&gt;Математические операции&lt;/h3&gt;
  &lt;p id=&quot;ZaYR&quot;&gt;Как и в других языках программирования, в переменные и свойства в Less можно записывать не только какие-то конечные значения — цвет, числовые значения, строки и т. д., но и различные комбинации, модификации, функции и так далее.&lt;/p&gt;
  &lt;p id=&quot;aLsL&quot;&gt;Например, самый простой вариант — в Less работают &lt;strong&gt;математические операции&lt;/strong&gt;:&lt;/p&gt;
  &lt;pre id=&quot;6cKM&quot; data-lang=&quot;less&quot;&gt;@cintainer-width: 150px;
@big-container-width: @container-width + 100; /* 250px */

@par-font-size: 16px;
@header-font-soze: @par-font-size * 1.5; /* 16 * 1.5 = 24 */

@cell-wudth: 50%;
@mini-cell-width: @cell-width / 2; /* 50% / 2 = 25% */&lt;/pre&gt;
  &lt;p id=&quot;LCVM&quot;&gt;Два основных нюанса при написании математических операций в Less:&lt;/p&gt;
  &lt;ul id=&quot;65ff&quot;&gt;
    &lt;li id=&quot;vYBx&quot;&gt;Вокруг операторов обязательно должны быть пробелы, иначе обработчик может воспринять их за часть строки.&lt;/li&gt;
    &lt;li id=&quot;aOOp&quot;&gt;Единица измерения берётся из первого параметра.&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;EMaV&quot;&gt;С числовыми значениями вполне всё очевидно, а вот с цветом не совсем — с ним тоже возможны математические операции, но операторы в любом случае будут работать с показателями RGB и влиять на все три цветовых показателя. &lt;/p&gt;
  &lt;p id=&quot;imwc&quot;&gt;При этом неважно как мы зададим цвет — ключевым словом, HEX или как-то еще — операция будет с показателями RGB:&lt;/p&gt;
  &lt;pre id=&quot;9aqo&quot; data-lang=&quot;less&quot;&gt;@rgb-color: rgb(110, 27, 255);
@keyword-color: red; /* эвкивалент rgb(255, 0, 0) */
@hex-color: #aa3399; /* эквивалент rgb(170, 51, 153) */

@new-rgb-color: @rgb-color + 20; /* = rgb(130, 47, 255) – 255 максимум */
@new-keyword-color: @keyword-color + 20; /* = rgb(255, 20, 20) */
@new-hex-color: @hex-color + 20; /* = rgb(190, 71, 173) */&lt;/pre&gt;
  &lt;p id=&quot;Nrir&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;ZDd3&quot;&gt;Цветовые функции&lt;/h3&gt;
  &lt;p id=&quot;KTb4&quot;&gt;Помимо математических операций в Less существуют и функции. Я уверен их достаточно много, но в тренажёре нас сначала знакомят в основном с цветовыми функциями, влияющими на тон, яркость и насыщенность. &lt;/p&gt;
  &lt;p id=&quot;4QCG&quot;&gt;Первая на очереди &lt;strong&gt;функция поворота цветового тона&lt;/strong&gt; &lt;code&gt;spin()&lt;/code&gt;, которая очень похожа на &lt;a href=&quot;https://blog.arkhelvetios.ru/css-filters-kekstagram#IuwB&quot; target=&quot;_blank&quot;&gt;CSS-фильтр&lt;/a&gt; &lt;code&gt;hue-rotate()&lt;/code&gt; и делает по сути тоже самое, но меняет именно значение конкретного цвета в свойстве, а не модифицирует уже отрисованный элемент.&lt;/p&gt;
  &lt;figure id=&quot;Fsuf&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/09/d9/09d9972f-f834-42c5-9391-bc14b4feb656.png&quot; width=&quot;393&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;9Rd4&quot;&gt;Функция принимает два аргумента — цвет или переменную с цветом и числовое значение угла поворота, причём без указания единицы измерений &lt;code&gt;deg&lt;/code&gt;:&lt;/p&gt;
  &lt;pre id=&quot;wiD1&quot; data-lang=&quot;less&quot;&gt;@not-red: spin(red, 60); /* повернет на 60deg по часовой на диаграме */
@true-red: spin(@not-red, -60); /* повернёт обратно, против часовой */

.green-box {
  background-color: spin(@true-red, 120); /* 120deg от red - зелёный */
}&lt;/pre&gt;
  &lt;p id=&quot;Ofb0&quot;&gt;Следующие две функции отвечают за &lt;strong&gt;уменьшение и увеличение яркости&lt;/strong&gt; цвета — &lt;code&gt;darken()&lt;/code&gt; и &lt;code&gt;lighten()&lt;/code&gt; соответственно. Функции тоже принимают два аргумента, первый — это цвет или переменная с цветом, а вторая значение увеличения яркости в процентах &lt;code&gt;%&lt;/code&gt;:&lt;/p&gt;
  &lt;pre id=&quot;dqS8&quot; data-lang=&quot;less&quot;&gt;@light-blue: lighten(blue, 50%);
@dark-blue: darken(blue, 50%);&lt;/pre&gt;
  &lt;p id=&quot;WRO7&quot;&gt;Во втором аргументе указывается именно процент воздействия на цвет, а не положение на шкале яркости. То есть при 100% значении &lt;code&gt;darken()&lt;/code&gt; получится чёрный цвет, а при 100% значении &lt;code&gt;lighten()&lt;/code&gt; получится белый, при этом при значении 0% — цвет не изменится.&lt;/p&gt;
  &lt;p id=&quot;kgeA&quot;&gt;И последние две функции из тренажёров отвечающие за &lt;strong&gt;уменьшение и увеличение насыщенности цвета&lt;/strong&gt; — &lt;code&gt;desaturate()&lt;/code&gt; и &lt;code&gt;saturate()&lt;/code&gt; соответственно. Синтаксис у них такой же как и у яркости:&lt;/p&gt;
  &lt;pre id=&quot;fGmm&quot; data-lang=&quot;less&quot;&gt;@more-blue: saturate(blue, 30%);
@greyly-blue: desaturate(blue, 50%);
@grey: desaturate(blue, 100%); /* 100% desaturate = оттенки серого */&lt;/pre&gt;
  &lt;p id=&quot;KO0s&quot;&gt;В первом аргументе всех этих функций можно использовать и сами функции, таким образом &lt;strong&gt;вкладывать&lt;/strong&gt; их друг в друга:&lt;/p&gt;
  &lt;pre id=&quot;ouxh&quot; data-lang=&quot;less&quot;&gt;@dark-greyly-yellow: darken(desaturate(yellow, 50%), 30%);&lt;/pre&gt;
  &lt;p id=&quot;yhPy&quot;&gt;Где всё это применимо? В тренажёре нам приводят в пример всплывающие подсказки и их стилизацию — мы задаём лишь один базовый цвет — фиолетовый, а всё остальное будь то цвет текста, фона и рамок даже разных сообщений мы выводим из базового используя вышеописанные функции.&lt;/p&gt;
  &lt;figure id=&quot;ibdw&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/45/f9/45f9520d-a1a8-4010-a55a-34ed56f843c8.png&quot; width=&quot;553&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;vXVi&quot;&gt;Таким образом меняя всего один параметр — базовый цвет, мы можем поменять палитру всех элементов. Используя эти инструменты по сути можно создавать целые «темы» интерфейса и менять их одним переключателем!&lt;/p&gt;
  &lt;p id=&quot;v13b&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;QJRd&quot;&gt;Вложенные правила&lt;/h3&gt;
  &lt;p id=&quot;3jPi&quot;&gt;Следующие возможности препроцессора связаны с CSS-правилами. Самое простое для понимания — в Less &lt;strong&gt;CSS-правила можно вкладывать друг в друга&lt;/strong&gt;:&lt;/p&gt;
  &lt;pre id=&quot;oZgh&quot; data-lang=&quot;less&quot;&gt;.card {
  color: @text-color;
  background-color: @bg-color;
  
  a {
    color: @link-color;
    text-decoration: none;
  }
}&lt;/pre&gt;
  &lt;p id=&quot;aAXd&quot;&gt;Что в CSS преобразуется как:&lt;/p&gt;
  &lt;pre id=&quot;ov6Y&quot; data-lang=&quot;less&quot;&gt;.card {
  color: red; /* цвета условные */
  background-color: black;
}
.card a {
  color: blue;
  text-decoration: none;
}&lt;/pre&gt;
  &lt;p id=&quot;Ua6e&quot;&gt;Такая древовидная вложенность в Less избавляет код от дублей и делает его более структурным, читаемым и наглядным.&lt;/p&gt;
  &lt;p id=&quot;4xfe&quot;&gt;При работе с такой вложенной структурой в Less есть еще один механизм позволяющий обращаться непосредственно &lt;strong&gt;к родительскому селектору&lt;/strong&gt; или к его подстроке:&lt;/p&gt;
  &lt;pre id=&quot;R3Ti&quot; data-lang=&quot;less&quot;&gt;.button {
  &amp;amp;-submit {
    color: @btn-text-color;
    background-color: @btn-bg-color;
    
    &amp;amp;:hover {
      background-color: lighten(@btn-bg-color, 30%);
    }
  }
  &amp;amp;-cancel {
    background-color: desaturate(@btn-bg-color, 50%);
  }
}&lt;/pre&gt;
  &lt;p id=&quot;8F1L&quot;&gt;Будет преобразовано в CSS как:&lt;/p&gt;
  &lt;pre id=&quot;cg7U&quot; data-lang=&quot;css&quot;&gt;.button-submit {
  color: white; /* цвета снова условные */
  background-color: red;
}

.button-submit:hover {
  background-color: lightred;
}

.button-cancel {
  background-color: #fa8072;
}&lt;/pre&gt;
  &lt;p id=&quot;OkLX&quot;&gt;Символ амперсанда &lt;code&gt;&amp;amp;&lt;/code&gt; приравнивается к строке указанной в родительском селекторе и таким образом можно обращаться сразу к группе селекторов в своем пространстве имён. &lt;/p&gt;
  &lt;p id=&quot;bPOp&quot;&gt;Также как и в примере, это используется при работе с псевдоклассами — иначе без подстановки &lt;code&gt;&amp;amp;&lt;/code&gt; перед &lt;code&gt;:hover&lt;/code&gt; конечный селектор в CSS выглядел бы как &lt;code&gt;.button-submit :hover&lt;/code&gt; — именно с пробелом.&lt;/p&gt;
  &lt;p id=&quot;liko&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;bF7F&quot;&gt;Примеси Less&lt;/h2&gt;
  &lt;p id=&quot;scty&quot;&gt;Следующая важная особенность Less — примеси, возможность «примешивать» содержимое одного правила в другой. Если в Less записать:&lt;/p&gt;
  &lt;pre id=&quot;EyDO&quot; data-lang=&quot;less&quot;&gt;.big { width: 500px; }

.white { color: white; }

.block {
  .big;
  .white;
}&lt;/pre&gt;
  &lt;p id=&quot;wHQh&quot;&gt;то в CSS преобразуется как:&lt;/p&gt;
  &lt;pre id=&quot;AQm7&quot; data-lang=&quot;css&quot;&gt;.big { width: 500px; }
.white { color: white; }
.block {
  width: 500px;
  color: white;
}&lt;/pre&gt;
  &lt;p id=&quot;u9YH&quot;&gt;Это самый примитивный вариант, однако, примеси это целый новый уровень абстракции, позволяющий создавать по сути чуть ли не функции. &lt;/p&gt;
  &lt;p id=&quot;VjSw&quot;&gt;Примесь в её более расширенном понимании — это &lt;strong&gt;комплексное Less-правило&lt;/strong&gt;, которое в итоге не выводится в конечный CSS, а применяется для структурного построения и которому можно даже задать аргументы. &lt;/p&gt;
  &lt;p id=&quot;NlFv&quot;&gt;На мой взгляд, примесь действительно похожа на функцию в обёртке CSS синтаксиса — выглядит она как обычный селектор со скобками:&lt;/p&gt;
  &lt;pre id=&quot;E85a&quot; data-lang=&quot;less&quot;&gt;.white() { color: white; } /* объявление примеси */
.text { .white(); }      /* применение примеси */&lt;/pre&gt;
  &lt;p id=&quot;Tnir&quot;&gt;При этом в CSS примесь никак не выводится:&lt;/p&gt;
  &lt;pre id=&quot;HzvI&quot; data-lang=&quot;css&quot;&gt;.text { color: white; }&lt;/pre&gt;
  &lt;p id=&quot;EXkJ&quot;&gt;Скобочки у примеси не просто так — на самом деле, в них можно передавать параметры, которые далее используются в примеси для её построения. Параметрам можно задать значение по умолчанию, в случае если при вызове примеси их не указали:&lt;/p&gt;
  &lt;pre id=&quot;g7CY&quot; data-lang=&quot;less&quot;&gt;.colors (@color) { /* параметр без значения по умолчанию */
  color: darken(@color, 30%);
  background-color: lighten(desaturate(@color, 20%) 20%);
}

.offset(@padding: 10px; @margin: 20px;) { /* со значениями по умолчанию */
  padding: @padding;
  margin: @margin;
}

.block {

  &amp;amp;-1 {
    .colors(blue);
    .offset(5px; 10px); /* значения сопоставляются по порядку */
  }
  
  &amp;amp;-2 {
    .colors(green);
    .offset();
  }
}&lt;/pre&gt;
  &lt;p id=&quot;UyvA&quot;&gt;Результат в CSS:&lt;/p&gt;
  &lt;pre id=&quot;0osz&quot; data-lang=&quot;css&quot;&gt;.block-1 {
  color: darkblue;
  background-color: lightskyblue;
  padding: 5px; /* значения при вызове примеси */
  margin: 10px;
}

.block-2 {
  color: darkgreen;
  background-color: lightseagreen;
  padding: 10px; /* значения по умолчанию */
  margin: 20px;
}&lt;/pre&gt;
  &lt;p id=&quot;WkEn&quot;&gt;Таким образом мы можем один раз задать какой-то набор свойств в виде примеси и в дальнейшем вызывать его в любом месте передавая только параметры. Особенно хорошо можно прочувствовать полезность примесей если поработать со свойствами типа &lt;code&gt;border-top-left-radius&lt;/code&gt; и написать их хотя бы несколько раз в чистом CSS.&lt;/p&gt;
  &lt;p id=&quot;rNyj&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;xUT3&quot;&gt;Шаблон примеси&lt;/h3&gt;
  &lt;p id=&quot;nLeg&quot;&gt;Можно пойти дальше и создать не просто какое-то количество разных примесей, а структурировать их и создать &lt;strong&gt;шаблоны для однотипных примесей&lt;/strong&gt;. &lt;/p&gt;
  &lt;p id=&quot;n8zJ&quot;&gt;Чтобы создать шаблон примеси, достаточно указать его имя в первом аргументе, перед параметрами примеси:&lt;/p&gt;
  &lt;pre id=&quot;6DcP&quot; data-lang=&quot;less&quot;&gt;.set-color(@color) { /* примесь */
  background-color: @color;
}
.set-font-size(lighten; @color) { /* шаблон примеси */
  background-color: lighten(@color, 50%);
}&lt;/pre&gt;
  &lt;p id=&quot;Ft0Y&quot;&gt;Самый тривиальный пример — шаблонизировать примеси для текста. Мы можем задать какой-то один базовый размер и от него плясать в зависимости от применяемой области.&lt;/p&gt;
  &lt;pre id=&quot;vUU7&quot; data-lang=&quot;less&quot;&gt;@base-font-size: 16px;

.set-font-size(@size) {
  font-size: @size;
  line-height: @size * 1.5;
}

.set-font-size(small, @size) {
  font-size: @size / 2;
  line-height: @size / 2;
}

.set-font-size(big, @size) {
  font-size: @size * 2;
  line-height: @size * 2 * 1.2;
}

.promo-header {
  .set-font-size(big, @base-font-size);
}
.promo-description {
  .set-font-size(@base-font-size);
}
.promo-note {
  .set-font-size(small, @base-font-size)
}&lt;/pre&gt;
  &lt;p id=&quot;X4Ew&quot;&gt;Результат в CSS:&lt;/p&gt;
  &lt;pre id=&quot;0sKr&quot; data-lang=&quot;css&quot;&gt;.promo-header {
  font-size: 32px; /* 16 * 2 = 32 */
  line-height: 38px; /* 16 * 2 * 1.2 = 32 * 1.2 = 38.4 */
}
.promo-description {
  font-size: 16px; 
  line-height: 24px; /* 16 * 1.5 = 24 */
}
.promo-note {
  font-size: 8px; /* 16 / 2 = 8 */
  line-height: 8px;
}&lt;/pre&gt;
  &lt;p id=&quot;Gix4&quot;&gt;Таким образом, у нас появляется, своего рода, пространство имён для примесей — лучше для однотипных задач использовать примеси с шаблонами, чем несколько разных примесей с разными названиями.&lt;/p&gt;
  &lt;p id=&quot;3ovX&quot;&gt;У шаблонов есть дополнительная фишка — &lt;strong&gt;универсальный шаблон&lt;/strong&gt;, который применяет указанные в нём параметры для всех одноименных примесей. Это полезно в случае если в каком-то наборе шаблонов примесей применяется один и тот же неизменяемый или одинаково изменяемый для всех шаблонов параметр.&lt;/p&gt;
  &lt;p id=&quot;Niuf&quot;&gt;Он обозначается зарезервированным именем &lt;code&gt;_@&lt;/code&gt; и на примере шаблонов для текста выше, мы можем, скажем, задать везде одинаковый &lt;code&gt;font-weight&lt;/code&gt;:&lt;/p&gt;
  &lt;pre id=&quot;OFUb&quot; data-lang=&quot;less&quot;&gt;.set-font-size(_@, @size) {
  font-weight: bold;
}&lt;/pre&gt;
  &lt;p id=&quot;WCad&quot;&gt;В итоге всем элементам, где были применены указанные примеси и их шаблоны будет подставлен этот параметр.&lt;/p&gt;
  &lt;p id=&quot;9XJd&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;JjQQ&quot;&gt;Примесь с условием&lt;/h3&gt;
  &lt;p id=&quot;zJaU&quot;&gt;Вот мы и дошли до «программируемой» части Less — условные конструкции с примесями! Логика, правда, немного отличается от привычной конструкции в языках программирования — мы не задаём условия «if/else», в которых пишем что будет происходить в их случае. &lt;/p&gt;
  &lt;p id=&quot;trD4&quot;&gt;Я немного порылся в англоязычной документации Less и там эта конструкция называется «Mixin Guards», то бишь «Охрана примеси». Суть, в общем-то, практически не меняется — мы ставим &lt;strong&gt;условие выполнения самой примеси&lt;/strong&gt; с помощью ключевого слова &lt;code&gt;when&lt;/code&gt;:&lt;/p&gt;
  &lt;pre id=&quot;Hyvm&quot; data-lang=&quot;less&quot;&gt;.set-font-size(@size) when (@size &amp;lt; 12px) {
  font-weigth: regular;
}&lt;/pre&gt;
  &lt;p id=&quot;g4S3&quot;&gt;Примесь выше сработает только если передаваемое значение, в нашем случае это размер шрифта, окажется меньше 12px.&lt;/p&gt;
  &lt;p id=&quot;ZluO&quot;&gt;В условие в скобках можно помещать как параметры самой примеси, так и внешние факторы, например, соответствие каких-то внешних переменных, причем их соответствие проверяется в момент вызова примеси:&lt;/p&gt;
  &lt;pre id=&quot;OiKP&quot; data-lang=&quot;less&quot;&gt;.set-font-color(@color) {
  color: @color;
}

.set-font-color(@color) when (@bg-color = black) {
  color: lighten(@color, 50%);
}

.first-text {
  .set-font-color(red); /* сработает безусловная примесь */
}

@bg-color: black; /* теперь условие корректно */

.second-text {
  .set-font-color(red); /* сработает условная примесь */
}&lt;/pre&gt;
  &lt;p id=&quot;IgFY&quot;&gt;В итоге в CSS получится:&lt;/p&gt;
  &lt;pre id=&quot;F4VA&quot; data-lang=&quot;css&quot;&gt;.first-text {
  color: red; /* безусловная примесь */
}

.second-text {
  color: lightred; /* примесь с условием */
}&lt;/pre&gt;
  &lt;p id=&quot;Sv9k&quot;&gt;Помимо этого, в условии или в «охране», можно использовать функции для &lt;strong&gt;проверки типа&lt;/strong&gt; передаваемых в примесь данных. Грубо говоря, строго типизировать нашу примесь:&lt;/p&gt;
  &lt;pre id=&quot;IyQM&quot; data-lang=&quot;less&quot;&gt;.mixin(@param) when (isnumber(@param)) { … }&lt;/pre&gt;
  &lt;p id=&quot;6fbw&quot;&gt;Функций проверки не так уж и много:&lt;/p&gt;
  &lt;ul id=&quot;oX9D&quot;&gt;
    &lt;li id=&quot;Lpaf&quot;&gt;&lt;code&gt;isnumber()&lt;/code&gt; — из примера выше, проверяет значение — любое числовое значение — просто число, пиксели, проценты и так далее, главное исчисляемое значение.&lt;/li&gt;
    &lt;li id=&quot;e0iX&quot;&gt;&lt;code&gt;iscolor()&lt;/code&gt; — проверка значение — цвет, любой вариант записи — ключевое слово, HEX, RGB и так далее;&lt;/li&gt;
    &lt;li id=&quot;e6BW&quot;&gt;&lt;code&gt;isstring()&lt;/code&gt; — проверка значение — строка, то есть значения свойств обёрнутые в кавычки &lt;code&gt;&amp;quot;...&amp;quot;&lt;/code&gt; — различные названия шрифтов, например;&lt;/li&gt;
    &lt;li id=&quot;MfFY&quot;&gt;&lt;code&gt;iskeyword()&lt;/code&gt; — проверка значение — ключевое слово, имеются ввиду ключевые слова в значениях свойств, кроме цветовых — &lt;code&gt;right&lt;/code&gt;, &lt;code&gt;center&lt;/code&gt;, &lt;code&gt;middle&lt;/code&gt; и так далее;&lt;/li&gt;
    &lt;li id=&quot;EAhL&quot;&gt;&lt;code&gt;isurl()&lt;/code&gt; — проверка значение — функция &lt;code&gt;url()&lt;/code&gt;, то есть проверка на значение-ссылку.&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;tQq6&quot;&gt;Есть еще несколько дополнительных, проверяющих конкретные единицы измерения — &lt;code&gt;ispixel()&lt;/code&gt;, &lt;code&gt;ispercentage()&lt;/code&gt; и &lt;code&gt;isem()&lt;/code&gt;. Там еще есть парочку, но про них нет смысла пока писать.&lt;/p&gt;
  &lt;p id=&quot;6WNs&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;oh3y&quot;&gt;Вставки&lt;/h3&gt;
  &lt;p id=&quot;ATVE&quot;&gt;В Less примеси — это целые правила, которые можно примешать к другим правилам. Но есть и возможность подставлять какие-то отдельные куски правил, свойств, значений, да в общем-то чего угодно. Называется это «вставка» или &lt;strong&gt;интерполяция переменных&lt;/strong&gt;.&lt;/p&gt;
  &lt;p id=&quot;IC5e&quot;&gt;В переменную мы можем записать по сути что угодно — число, строку, ключевое слово даже часть названия селектора. То есть, переменную не обязательно использовать только как носитель чего-то значимого с точки зрения CSS, это может быть и часть структуры Less.&lt;/p&gt;
  &lt;p id=&quot;8TEX&quot;&gt;Дальше чтобы значение этой переменной подставить в нужном месте используется фигурные скобки вокруг имени — &lt;code&gt;@{var}&lt;/code&gt;:&lt;/p&gt;
  &lt;pre id=&quot;eknN&quot; data-lang=&quot;less&quot;&gt;@state: success;
@property: color;
@icon: &amp;quot;question&amp;quot;;

.btn-@{state} { /* как часть селектора */
  background-color: green;
}
.btn-error {
  background-@{property}: red; /* как часть свойства */
}
.btn-help {
  background-image: url(&amp;quot;/img/icons/@{icon}.png&amp;quot;); /* как часть url */
}&lt;/pre&gt;
  &lt;p id=&quot;rAHR&quot;&gt;Результат в CSS:&lt;/p&gt;
  &lt;pre id=&quot;mxah&quot; data-lang=&quot;css&quot;&gt;.btn-success {
  background-color: green;
}
.btn-error {
  background-color: red;
}
.btn-help {
  background-image: url(&amp;quot;/img/icons/question.png&amp;quot;);
}&lt;/pre&gt;
  &lt;p id=&quot;YYf2&quot;&gt;Еще одна особенность Less, про которую упомянули в этом уроке, но которая на мой скромный взгляд очень важна — это своеобразное &lt;strong&gt;экранирование&lt;/strong&gt; или такой режим строки, содержимое которой при вызове не изменяется, то есть игнорируется весь Less синтаксис кроме интерполяций.&lt;/p&gt;
  &lt;p id=&quot;9FoW&quot;&gt;Задаётся такая строка с помощью кавычек и знака тильды &lt;code&gt;~&amp;quot;...&amp;quot;&lt;/code&gt;, это позволяет записывать в строку, а как следствие в переменную или в значение целые выражения и даже свойства с подставляемым значением:&lt;/p&gt;
  &lt;pre id=&quot;KTvD&quot; data-lang=&quot;less&quot;&gt;@base-size: 10;
@base-color: red;
@default-border: ~&amp;quot;@{base-size}px solid&amp;quot;; /* интерполяция */
/* почему-то подкрашено в другой цвет, но это тоже переменная */

.border-colored(@color) {
  border: @default-border @color;
  }

.element {
  .border-colored(@base-color);
  }&lt;/pre&gt;
  &lt;p id=&quot;TtYt&quot;&gt;Пример прям конкретно говнокодерский, но мне что-то адекватное в голову никак не приходит, но я почему-то уверен, что область применений экранирования очень большая. В CSS выводится вот что:&lt;/p&gt;
  &lt;pre id=&quot;W4iX&quot; data-lang=&quot;css&quot;&gt;.element {
  border: 10px solid red;
}&lt;/pre&gt;
  &lt;p id=&quot;gQIi&quot;&gt;Без интерполяции значения в экранированную строку переменная с числом не «склеивается» корректно с единицами измерений. То есть &lt;code&gt;10&lt;/code&gt; и &lt;code&gt;px&lt;/code&gt; не объединяются в одну сущность. Хотя, судя по англоязычной документации — это постепенно исправляется и много в каких случаях экранирование уже не нужно.&lt;/p&gt;
  &lt;p id=&quot;HuRA&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;tl70&quot;&gt;Циклы&lt;/h3&gt;
  &lt;p id=&quot;7PDm&quot;&gt;Напоследок разберёмся — можно ли в Less делать циклы? Ответ — можно, но встроенных решений в Less для этого нет. В тренажёре описывается хитрый способ создания цикла с помощью примеси с условием и интерполяцией.&lt;/p&gt;
  &lt;p id=&quot;A6YO&quot;&gt;Я не зря писал, что примеси похожи на функции и их как и функцию можно рекурсивно зациклить используя аргумент как счётчик:&lt;/p&gt;
  &lt;pre id=&quot;Dyq5&quot; data-lang=&quot;less&quot;&gt;.mixin(@n) {
  .mixin(@n + 1); /* приращение */
}
.mixin(1);&lt;/pre&gt;
  &lt;p id=&quot;JqWm&quot;&gt;Чтобы цикл был не бесконечный можно использовать примесь с условием, в котором указать момент завершения цикла, например достижение счётчиком определенного значения:&lt;/p&gt;
  &lt;pre id=&quot;uowA&quot; data-lang=&quot;less&quot;&gt;.mixin(@n) when (@n =&amp;lt; 3) { /* при @n &amp;gt; 3 примесь не выполняется */
   .mixin(@n + 1);
}
.mixin(1);&lt;/pre&gt;
  &lt;p id=&quot;KWN9&quot;&gt;Вполне себе цикл, который можно использовать, например, для создания селекторов с одинаковым префиксом, но разными суффиксами, используя интерполяцию значения счётчика:&lt;/p&gt;
  &lt;pre id=&quot;Y81o&quot; data-lang=&quot;less&quot;&gt;.mixin(@n) when (@n =&amp;lt; 3)
   .block-@{n} {
     ...
   }
   
   .mixin(@n + 1);
}
.mixin(1);&lt;/pre&gt;
  &lt;p id=&quot;YsZO&quot;&gt;Что в CSS преобразуется как:&lt;/p&gt;
  &lt;pre id=&quot;xXgA&quot; data-lang=&quot;css&quot;&gt;.block-3 {...}
.block-2 {...}
.block-1 {...}&lt;/pre&gt;
  &lt;p id=&quot;8yQQ&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;0aoH&quot;&gt;Испытания&lt;/h2&gt;
  &lt;p id=&quot;yRCq&quot;&gt;Решил вывести их отдельно для обеих частей блока. Все они по сути об одном, плюс я немного переформатировал повествование.&lt;/p&gt;
  &lt;p id=&quot;g3ub&quot;&gt;Первое испытание на цветовые функции — у нас уже есть некоторые области с цветами, а отталкиваясь от них нужно заполнить остальные:&lt;/p&gt;
  &lt;figure id=&quot;h88A&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://sun9-56.userapi.com/impf/oUT2YqCO90Bh7TmX88bAiN8jkfyV3YWAB6TW_A/9AfSmKjGyyY.jpg?size=1322x924&amp;quality=96&amp;sign=aaa5bb39805fcddcb1e67e7df99cdda8&amp;type=album&quot; width=&quot;1322&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;25hG&quot;&gt;Следующее два испытания на понимание работы примесей и их параметров, как со значениями по умолчанию так и без. Плюс, немного вспоминаем про двумерные трансформации:&lt;/p&gt;
  &lt;figure id=&quot;dO3t&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://sun9-19.userapi.com/impf/UASK09IXVlA9nuS4JpeUCFER-qF27SR9hLfpxg/DZXgXsy_M8k.jpg?size=1319x920&amp;quality=96&amp;sign=fe85b34fcd963b85ca3b7aaae3e507e1&amp;type=album&quot; width=&quot;1319&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;M4JS&quot;&gt;Третье испытание модифицируется шаблонами примесей:&lt;/p&gt;
  &lt;figure id=&quot;oM64&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://sun9-82.userapi.com/impf/FPZeQruZdFKQId4KD7wYBF_bPC-h5GpfvFLhAA/JwnZzUBUeFE.jpg?size=1318x921&amp;quality=96&amp;sign=5ddc1a76f849c4b2a398f560779dfcb1&amp;type=album&quot; width=&quot;1318&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;mm98&quot;&gt;Четвёртое испытание полностью на понимание работы условных примесей — нужно расставить существующим примесям условия, чтобы они срабатывали только для определённых элементов:&lt;/p&gt;
  &lt;figure id=&quot;NKz8&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://sun9-70.userapi.com/impf/d1FQAD-QEyyzimXMma0tgBMOAa_aYb3mskIpPQ/yET_9mnAhow.jpg?size=1321x922&amp;quality=96&amp;sign=879e20ff3c83b5b8da8cce769c517974&amp;type=album&quot; width=&quot;1321&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;27lP&quot;&gt;Пятое испытание на создание цикла с использованием интерполяции. Не уверен, что решение того требовало, но я еще использовал и экранирование:&lt;/p&gt;
  &lt;figure id=&quot;t6ov&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://sun9-4.userapi.com/impf/Xu5MLLMxEhqb8b5BoXEHd_jjQaV-11ELVz_oUA/yPQ9V2keHEI.jpg?size=1321x922&amp;quality=96&amp;sign=722866a2ba6ce3ddcde76a5e4797afb4&amp;type=album&quot; width=&quot;1321&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;5TbS&quot;&gt;Последнее испытание комбинирует всё пройденное — все примеси созданы, но не применены к элементам, нужно все корректно склеить:&lt;/p&gt;
  &lt;figure id=&quot;lMuD&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://sun9-29.userapi.com/impf/LmCySx3Mz7hcd-CFUcMMqu71vys8Yq26xb7wxg/7nsimu4pIJo.jpg?size=1319x922&amp;quality=96&amp;sign=d098805bc7d11a6b6f9a0cd3f69eaac9&amp;type=album&quot; width=&quot;1319&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;9dAO&quot;&gt;&lt;/p&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;CmUm&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;HQIr&quot;&gt;Не самый простой был блок, но очень интересный! У меня, правда, по ходу прохождения возникло много вопросов — например, пресеты цветов можно явно использовать в динамическом изменении цветовой схемы. Как оно будет работать — нужно всё-таки инициировать обновление страницы, чтобы сработал препроцессор и пересобрал все? Или можно как-то с помощью JS это все настроить в динамике в моменте?&lt;/p&gt;
  &lt;p id=&quot;7FlZ&quot;&gt;Еще я понял, что тут ну прям о-очень небольшая часть от Less, гуляя по документации обнаружил много интересных штук. Так что к Less я еще вернусь, но у же в рамках чего-то другого.&lt;/p&gt;
  &lt;p id=&quot;FXah&quot;&gt;А вам большое спасибо за внимание! Желаю вам пережить эту жару с максимальным комфортом!&lt;/p&gt;
  &lt;p id=&quot;86dx&quot;&gt;Ссылки на мои социальные сети, там анонсы постов, некоторые мои короткие записи, мыслишки и всякое на отвлечённые темы:&lt;/p&gt;
  &lt;section&gt;
    &lt;p id=&quot;kfMs&quot; data-align=&quot;center&quot;&gt;&lt;a href=&quot;https://t.me/arkhelvetios&quot; target=&quot;_blank&quot;&gt;Telegram&lt;/a&gt; — &lt;a href=&quot;https://twitter.com/arkhelvetios&quot; target=&quot;_blank&quot;&gt;Twitter&lt;/a&gt; — &lt;a href=&quot;https://www.instagram.com/arkhelvetios/&quot; target=&quot;_blank&quot;&gt;Instagram&lt;/a&gt; — &lt;a href=&quot;https://vk.com/arkhelvetios&quot; target=&quot;_blank&quot;&gt;VK&lt;/a&gt;&lt;/p&gt;
  &lt;/section&gt;
  &lt;p id=&quot;qKEx&quot;&gt;Заходите куда удобно вам и подписывайтесь! Еще раз спасибо за внимание!&lt;/p&gt;
  &lt;tt-tags id=&quot;eUyi&quot;&gt;
    &lt;tt-tag name=&quot;css&quot;&gt;#css&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;css3&quot;&gt;#css3&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;less&quot;&gt;#less&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;frontend&quot;&gt;#frontend&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;front_end&quot;&gt;#front_end&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;обучение&quot;&gt;#обучение&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;it&quot;&gt;#it&lt;/tt-tag&gt;
  &lt;/tt-tags&gt;

</content></entry><entry><id>helvetios:transition-and-animation</id><link rel="alternate" type="text/html" href="https://teletype.in/@helvetios/transition-and-animation?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=helvetios"></link><title>Плавные переходы, Кривые Безье и CSS-анимация — Тренажёр HTML Academy</title><published>2022-06-29T08:26:20.552Z</published><updated>2022-06-29T08:26:20.552Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img3.teletype.in/files/ec/d9/ecd96d7b-8d82-4d86-a86a-33166dfebd38.png"></media:thumbnail><category term="webdev" label="Веб-разработка"></category><tt:hashtag>html</tt:hashtag><tt:hashtag>css</tt:hashtag><tt:hashtag>html5</tt:hashtag><tt:hashtag>css3</tt:hashtag><tt:hashtag>frontend</tt:hashtag><tt:hashtag>front_end</tt:hashtag><tt:hashtag>обучение</tt:hashtag><tt:hashtag>it</tt:hashtag><summary type="html">&lt;img src=&quot;https://img4.teletype.in/files/b8/fd/b8fd3350-ca19-4695-bcd9-53c21c674227.png&quot;&gt;Наконец, я добрался до анимации в CSS! Для начала вспомним про трансформации, разберёмся как сделать их плавными и затем перейдем уже к анимации по ключевым кадрам!</summary><content type="html">
  &lt;figure id=&quot;p5Ah&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/b8/fd/b8fd3350-ca19-4695-bcd9-53c21c674227.png&quot; width=&quot;1200&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;fBKy&quot;&gt;Наконец, я добрался до анимации в CSS! Для начала вспомним про трансформации, разберёмся как сделать их плавными и затем перейдем уже к анимации по ключевым кадрам!&lt;/p&gt;
  &lt;p id=&quot;jhXK&quot;&gt;Кстати, я не прогадал, когда решил пройти сначала &lt;a href=&quot;https://blog.arkhelvetios.ru/css-tricks-part1&quot; target=&quot;_blank&quot;&gt;Тонкости&lt;/a&gt; — в части про переходы мы будем по полной эксплуатировать тему с &lt;code&gt;:checked&lt;/code&gt; и &lt;code&gt;~&lt;/code&gt; селектором. Вообще, появилась у меня мыслишка запилить что-нибудь с использованием этого инструмента. Просто for fun и ради, своего рода, тренировки.&lt;/p&gt;
  &lt;p id=&quot;2dmo&quot;&gt;&lt;/p&gt;
  &lt;nav&gt;
    &lt;ul&gt;
      &lt;li class=&quot;m_level_1&quot;&gt;&lt;a href=&quot;#GFMg&quot;&gt;Плавные переходы&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_2&quot;&gt;&lt;a href=&quot;#Rvtn&quot;&gt;Свойства перехода&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_2&quot;&gt;&lt;a href=&quot;#d16h&quot;&gt;Функция перехода&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_2&quot;&gt;&lt;a href=&quot;#P2BI&quot;&gt;Мини-мастерская переходов&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_1&quot;&gt;&lt;a href=&quot;#hy1S&quot;&gt;CSS Анимация&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_2&quot;&gt;&lt;a href=&quot;#jvu8&quot;&gt;Ключевые кадры&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_2&quot;&gt;&lt;a href=&quot;#c0Ei&quot;&gt;Свойства анимации&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/nav&gt;
  &lt;p id=&quot;TERu&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;GFMg&quot;&gt;Плавные переходы&lt;/h2&gt;
  &lt;p id=&quot;ebCu&quot;&gt;Мы немного затрагивали плавные переходы, когда разбирали какие бывают &lt;a href=&quot;https://blog.arkhelvetios.ru/position-and-transform#ZPgz&quot; target=&quot;_blank&quot;&gt;трансформации&lt;/a&gt;, но по умолчанию, все они происходят мгновенно. Точнее трансформацией &lt;code&gt;transform&lt;/code&gt; мы лишь задавали разные свойства состояния — у элемента их может быть несколько, например, базовое и &lt;code&gt;:hover&lt;/code&gt;. &lt;/p&gt;
  &lt;p id=&quot;Mm3F&quot;&gt;Переход же между этими состояниями мгновенен и за плавность или, как написали в тренажёре, «нежность» перехода из одного состояния элемента в другой отвечает семейство свойств &lt;code&gt;transitions&lt;/code&gt;.&lt;/p&gt;
  &lt;p id=&quot;PIJ3&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;Rvtn&quot;&gt;Свойства перехода&lt;/h3&gt;
  &lt;p id=&quot;dkT0&quot;&gt;Первое и самое важное свойство, без которого вообще не работает плавность переходов — свойство &lt;strong&gt;длительности перехода&lt;/strong&gt; &lt;code&gt;transition-duration&lt;/code&gt;. Оно принимает числовое значение в секундах &lt;code&gt;s&lt;/code&gt; или миллисекундах &lt;code&gt;ms&lt;/code&gt;:&lt;/p&gt;
  &lt;pre id=&quot;Ww3D&quot; data-lang=&quot;css&quot;&gt;transition-duration: 0.3s; 
transition-duration: 300ms; &lt;/pre&gt;
  &lt;p id=&quot;OY1a&quot;&gt;По умолчанию, свойства семейства &lt;code&gt;transitions&lt;/code&gt; принимают во внимание все свойства, которые можно плавно изменить или анимировать — это размерные, цветовые и позиционные свойства. Чтобы контролировать &lt;strong&gt;какой конкретно параметр&lt;/strong&gt; нужно изменять, используется свойство &lt;code&gt;transition-property&lt;/code&gt;.&lt;/p&gt;
  &lt;p id=&quot;kuCb&quot;&gt;По умолчанию имеет значение &lt;code&gt;all&lt;/code&gt;, то бишь все, в иных случаях принимает буквально названия CSS-свойств на которые будет распространяться плавный переход и его параметры. Можно задавать сразу несколько параметров через запятую — в этом плане работает схема из &lt;code&gt;background&lt;/code&gt;, значения сопоставляются по их позиции:&lt;/p&gt;
  &lt;pre id=&quot;G2rX&quot; data-lang=&quot;css&quot;&gt;transition-property: width, height;
transition-duration: 1s, 5s; /* ширина меняется за 1s, высота за 5s */&lt;/pre&gt;
  &lt;p id=&quot;GYBX&quot;&gt;Следующее полезное свойство — &lt;strong&gt;задержка перехода&lt;/strong&gt; &lt;code&gt;transition-delay&lt;/code&gt;. Как и длительность принимает значение секунд &lt;code&gt;s&lt;/code&gt; и миллисекунд &lt;code&gt;ms&lt;/code&gt;. Критично необходимое свойство при создании плавной анимации интерфейсов, хотя для новичков может показаться иначе.&lt;/p&gt;
  &lt;p id=&quot;8ZWA&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;d16h&quot;&gt;Функция перехода&lt;/h3&gt;
  &lt;p id=&quot;esZe&quot;&gt;Последнее свойство супер полезное, но и достаточно сложное для понимания — это свойство &lt;strong&gt;функции перехода&lt;/strong&gt; &lt;code&gt;transition-timing-function&lt;/code&gt;. Все переходы помимо длительности имеют, можно сказать, «скорость» перехода — она может быть постоянной или «линейной», а может быть более сложной, например, замедляться в начале или в конце.&lt;/p&gt;
  &lt;p id=&quot;MdIT&quot;&gt;Отношение времени к изменению состояния можно, условно, записать в функцию, а построив график этой функции можно наглядно посмотреть как будет вести себя элемент. Именно эту функцию принимает за значение свойство &lt;code&gt;transition-timing-function&lt;/code&gt;.&lt;/p&gt;
  &lt;figure id=&quot;cDGZ&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/09/1e/091e952c-3ce3-440a-acc0-59061f2acdf2.png&quot; width=&quot;543&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;n6Ex&quot;&gt;Но не стоит пугаться математики! Во-первых, математика проще чем думает большинство, но об этом как-нибудь в другой раз. Во-вторых, для нашего свойства есть заготовки функций в виде ключевых слов:&lt;/p&gt;
  &lt;ul id=&quot;g5pb&quot;&gt;
    &lt;li id=&quot;vg7K&quot;&gt;&lt;code&gt;ease&lt;/code&gt; — значение по умолчанию для всех переходов, немного замедляется в начале, резкий переход в середине и плавное замедление к концу;&lt;/li&gt;
    &lt;li id=&quot;GQep&quot;&gt;&lt;code&gt;linear&lt;/code&gt; — линейный, равномерный переход, без ускорений и замедлений;&lt;/li&gt;
    &lt;li id=&quot;gHNK&quot;&gt;&lt;code&gt;ease-in&lt;/code&gt; — слегка замедляется на старте;&lt;/li&gt;
    &lt;li id=&quot;T69U&quot;&gt;&lt;code&gt;ease-out&lt;/code&gt; — слегка замедляется в конце;&lt;/li&gt;
    &lt;li id=&quot;1Q8d&quot;&gt;&lt;code&gt;ease-in-out&lt;/code&gt; — похож на &lt;code&gt;ease&lt;/code&gt;, но имеет более резкий переход в середине.&lt;/li&gt;
  &lt;/ul&gt;
  &lt;figure id=&quot;Hk9s&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/dc/5b/dc5bd896-d6ea-48b9-9a72-6556b2b5255a.png&quot; width=&quot;810&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;pDAF&quot;&gt;На самом деле все эти функции являются упрощёнными образами функций кубических &lt;a href=&quot;https://ru.wikipedia.org/wiki/%D0%9A%D1%80%D0%B8%D0%B2%D0%B0%D1%8F_%D0%91%D0%B5%D0%B7%D1%8C%D0%B5&quot; target=&quot;_blank&quot;&gt;Кривых Безье&lt;/a&gt;. Свойство &lt;code&gt;transition-timing-function&lt;/code&gt; может принимать значение в виде самой функции &lt;code&gt;cubic-bezier(x1, y1, x2, y2)&lt;/code&gt;, где аргументами являются координаты опорных точек.&lt;/p&gt;
  &lt;p id=&quot;kZFX&quot;&gt;Что за опорные точки? Те кто хотя бы раз в жизни работал с векторной графикой в каком-нибудь Adobe Illustrator уже знают про кривые Безье, хотя могут об этом и не догадываться. Зато опорные точки они точно видели.&lt;/p&gt;
  &lt;figure id=&quot;w1R8&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/9a/d0/9ad06117-fb6b-492c-95be-58e7e452668a.png&quot; width=&quot;499&quot; /&gt;
    &lt;figcaption&gt;Это из Иллюстратора&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;KKbZ&quot;&gt;Итак, разбираемся. Обычный отрезок состоит из двух точек — начало и конец отрезка. У этих точек могут быть свои координаты, но для упрощения сделаем начало в нуле &lt;code&gt;0&lt;/code&gt;, а конец в единице по обеим осям &lt;code&gt;1, 1&lt;/code&gt;. &lt;/p&gt;
  &lt;p id=&quot;hFwE&quot;&gt;Получается прямая линия, как на графике с линейной &lt;code&gt;linear&lt;/code&gt; функцией (см. выше), но нас больше интересуют кривые. Как нам их деформировать? Нужно добавить больше точек! Точнее две — по одной для начала и для конца. &lt;/p&gt;
  &lt;p id=&quot;5zYj&quot;&gt;Соединив эти опорные точки с началом и концом мы получим ломанную кривую, очень отдалённо похожую на то, что нам надо:&lt;/p&gt;
  &lt;figure id=&quot;mz7o&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/c5/97/c597f778-5d09-4b43-8e78-e3a4c99b5e97.png&quot; width=&quot;627&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;L26e&quot;&gt;Плавной её делает уже «магия» математики, вдаваться в её подробности не будем, но всю эту магию несёт в себе сама функция &lt;code&gt;cubic-bezier()&lt;/code&gt;. В любимой Википедии отлично показывается как строится плавная кривая из ломанной, если кому-то интересно.&lt;/p&gt;
  &lt;figure id=&quot;9ZvO&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://upload.wikimedia.org/wikipedia/commons/d/db/B%C3%A9zier_3_big.gif&quot; width=&quot;360&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;UuhY&quot;&gt;Наша функция &lt;code&gt;cubic-bezier()&lt;/code&gt; в аргументы принимает координаты опорной точки начала — &lt;code&gt;x1&lt;/code&gt; по горизонтали, &lt;code&gt;y1&lt;/code&gt; по вертикали, и аналогично опорной точки конца — &lt;code&gt;x2&lt;/code&gt; и &lt;code&gt;y2&lt;/code&gt;. &lt;/p&gt;
  &lt;p id=&quot;wb60&quot;&gt;Координаты могут совпадать, как друг с другом, так и с крайними точками. Например, линейная &lt;code&gt;linear&lt;/code&gt;, формально, тоже имеет опорные точки, просто их координаты совпадают с началом и концом:&lt;/p&gt;
  &lt;pre id=&quot;2OQV&quot; data-lang=&quot;css&quot;&gt;cubic-bezier(0, 0, 1, 1)&lt;/pre&gt;
  &lt;p id=&quot;9Ob3&quot;&gt;У &lt;code&gt;ease-in&lt;/code&gt; и &lt;code&gt;ease-out&lt;/code&gt; совпадают координаты одной из опорных точек:&lt;/p&gt;
  &lt;pre id=&quot;ZkFi&quot; data-lang=&quot;css&quot;&gt;cubic-bezier(0.42, 0, 1, 1) /* ease-in */
cubic-bezier(0, 0, 0.58, 1) /* ease-out */&lt;/pre&gt;
  &lt;p id=&quot;MuBo&quot;&gt;Естественно, на эту тему есть уже много сервисов, одно из них рекомендует Академия — &lt;a href=&quot;https://cubic-bezier.com/&quot; target=&quot;_blank&quot;&gt;https://cubic-bezier.com/&lt;/a&gt; — в нём можно поиграться с опорными точками и построить ту функцию, которая вам нужна. Другой вопрос, что в 90% случаях хватает &lt;code&gt;ease&lt;/code&gt; и её производных, но для оставшихся 10% пригодиться!&lt;/p&gt;
  &lt;p id=&quot;adil&quot;&gt;На последок — у свойства &lt;code&gt;transition-timing-function&lt;/code&gt; есть еще одно значение! Это тоже функция — &lt;code&gt;steps()&lt;/code&gt;, она преобразует переход в пошаговый. Она принимает два аргумента, первый — количество шагов, а второй — одно из двух ключевых слов &lt;code&gt;start&lt;/code&gt; или &lt;code&gt;end&lt;/code&gt;. &lt;/p&gt;
  &lt;p id=&quot;bjbm&quot;&gt;При заданном &lt;code&gt;start&lt;/code&gt; первый шаг выполняется одновременно с началом перехода, а в случае c &lt;code&gt;end&lt;/code&gt; последний шаг будет выполнен вместе с завершением перехода. Грубо говоря, указывается под что подстроится функция.&lt;/p&gt;
  &lt;p id=&quot;bzY6&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;P2BI&quot;&gt;Мини-мастерская переходов&lt;/h3&gt;
  &lt;p id=&quot;24lC&quot;&gt;Больше половины части занимают именно примеры, так как свойств на самом деле не много. Я сначала хотел их пропустить, но решил, что хотя бы упомяну, так как сделано реально интересно и делаем прикольные штуки.&lt;/p&gt;
  &lt;p id=&quot;Fk99&quot;&gt;Первым делом мы сделали самое очевидное — кнопочки. Смена происходит через добавление класса с помощью JS. Добавили еще эффект расширения тени, который, на мой взгляд, сделан хреновенько:&lt;/p&gt;
  &lt;figure id=&quot;hVAH&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/bd/29/bd29ccfb-2303-48cd-bef2-0e38cd03f94e.gif&quot; width=&quot;300&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;4ogF&quot;&gt;Следом сделали красивые чекбоксы. Здесь и далее уже используется &lt;code&gt;:checked&lt;/code&gt; и селектор &lt;code&gt;~&lt;/code&gt; для стилизации псевдоэлементов выбранных пунктов. Сама идея с галочкой из поля прикольная, но явно требует доработать момент возвращения галочки в состояние пустого квадрата, а то стороны начинают появляться раньше чем надо:&lt;/p&gt;
  &lt;figure id=&quot;BKNy&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/f8/ce/f8ce3f6d-ed63-4d50-9102-36fc0a006531.gif&quot; width=&quot;200&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;dNP8&quot;&gt;Далее, конечно же, потренировались на радиокнопках, тут всё ещё проще — два псевдоэлемента, один перекрывает другой при выделении, анимирована &lt;code&gt;scale()&lt;/code&gt; трансформация:&lt;/p&gt;
  &lt;figure id=&quot;ZIch&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/36/cb/36cb516f-6338-489f-8b7e-85dae18f019c.gif&quot; width=&quot;204&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;2jhW&quot;&gt;Следом сделали переключатели — их достаточно большое количество в интерфейсах. Здесь мы сделали их через чекбоксы — один псевдоэлемент это линия, а второй анимируемый ползунок, простой translate со сменой цвета:&lt;/p&gt;
  &lt;figure id=&quot;24kq&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/19/93/199307c2-e396-436e-afff-c1374fb321ba.gif&quot; width=&quot;232&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;PqEC&quot;&gt;Следующим мы сделали так называемый «бургер» &lt;s&gt;и точка&lt;/s&gt; меню, обычно такие делают в мобильных приложениях или в мобильных версиях сайта. Честно скажу, я до этого делал их тупо через смену картинок, не приходило в голову делать через элементы и псевдоэлементы. А подобные анимации, я думал, делаются исключительно через JS, но нет! &lt;/p&gt;
  &lt;figure id=&quot;oq4f&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/59/80/5980a51b-bf1c-47db-a7fb-45a5dd5321fd.gif&quot; width=&quot;192&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;fPqy&quot;&gt;И на последок поигрались с полями формы. Поле формы тоже одно из самых «труднодоступных» для стилизации элементов. Здесь мы используем &lt;code&gt;&amp;lt;label&amp;gt;&lt;/code&gt; как &lt;code&gt;placeholder&lt;/code&gt; и псевдоэлементы как подчеркивания:&lt;/p&gt;
  &lt;figure id=&quot;Pgzo&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/7a/20/7a2065b2-775a-434c-8e1c-b17a091526bb.gif&quot; width=&quot;352&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;aQvF&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;hy1S&quot;&gt;CSS Анимация&lt;/h2&gt;
  &lt;p id=&quot;yolL&quot;&gt;Мы можем управлять стилями некоторых состояний одного элемента, например, выбранным &lt;code&gt;:checked&lt;/code&gt;, наведённым &lt;code&gt;:hover&lt;/code&gt;, ну и базовым. Выше мы разобрали как сделать плавный переход между этими заготовленными состояниями, то есть между двумя стилями, с помощью семейства свойств &lt;code&gt;transition&lt;/code&gt;.&lt;/p&gt;
  &lt;p id=&quot;4xS2&quot;&gt;И хотя сами по себе переходы очень крутой инструмент и решает, наверное, большую часть задач анимации в интерфейсах, всё же мы можем пойти дальше — с помощью CSS &lt;strong&gt;создавать сложные анимации&lt;/strong&gt; с большим количеством состояний одного элемента и переходов между ними. За это отвечает семейство свойств &lt;code&gt;animation&lt;/code&gt;.&lt;/p&gt;
  &lt;p id=&quot;T0UX&quot;&gt;Сама анимация в CSS состоит из двух частей — функция самой анимации или, как её назвали в тренажёре, &lt;strong&gt;набор ключевых кадров&lt;/strong&gt; &lt;code&gt;@keyframes&lt;/code&gt; и самих свойств семейства &lt;code&gt;animation&lt;/code&gt;, которые применяются к элементам.&lt;/p&gt;
  &lt;p id=&quot;Kj6n&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;jvu8&quot;&gt;Ключевые кадры&lt;/h3&gt;
  &lt;p id=&quot;HUCH&quot;&gt;Сначала разберёмся с ключевыми кадрами &lt;code&gt;@keyframes&lt;/code&gt; — если сильно упростить описание этой конструкции, то с её помощью мы задаём состояния элемента — ключевые кадры, и стили этих состояний в нужный момент анимации:&lt;/p&gt;
  &lt;pre id=&quot;GGID&quot; data-lang=&quot;css&quot;&gt;@keyframes stretching { /* название функции-анимации */
  0% { /* состояние в начале */
    width: 100px;
  }
  100% { /* состояние в конце */
    width: 200px;
  }
}&lt;/pre&gt;
  &lt;p id=&quot;mKFe&quot;&gt;Конструкция похожа, на мой взгляд, на объявление какой-либо функции из любого C-подобного языка, что недалеко от правды. Мы объявляем, что функция &lt;code&gt;stretching&lt;/code&gt; — это анимация, которая изменит элемент от состояния ключевого кадра &lt;code&gt;0%&lt;/code&gt;, до состояния ключевого кадра &lt;code&gt;100%&lt;/code&gt;.&lt;/p&gt;
  &lt;p id=&quot;eRMI&quot;&gt;Имя анимации можно задавать любое, главное помнить, что оно чувствительно к регистру. Ключевые кадры обозначаются либо процентами, либо есть два ключевых слова — &lt;code&gt;from&lt;/code&gt;, что по сути равно &lt;code&gt;0%&lt;/code&gt; и &lt;code&gt;to&lt;/code&gt;, что равно &lt;code&gt;100%&lt;/code&gt;.&lt;/p&gt;
  &lt;pre id=&quot;j8Sq&quot; data-lang=&quot;css&quot;&gt;@keyframes square-move {
  from   {top: 0px; left: 0px; background: red;}
  25%  {top: 0px; left: 100px; background: blue;}
  50%  {top: 100px; left: 100px; background: yellow;}
  75%  {top: 100px; left: 0px; background: green;}
  to {top: 0px; left: 0px; background: red;}
}&lt;/pre&gt;
  &lt;figure id=&quot;Df3z&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/e4/43/e44303e8-3555-4c58-a7c1-5583cfbfc62f.gif&quot; width=&quot;213&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;Dajy&quot;&gt;Кадры можно группировать, если какое-то состояние одинаково для двух моментов анимации. Это используется в разных целях, например, анимацию &lt;code&gt;square-move&lt;/code&gt; можно немного сократить:&lt;/p&gt;
  &lt;pre id=&quot;Lz0X&quot; data-lang=&quot;css&quot;&gt;@keyframes square-move {
  from, to   {top: 0px; left: 0px; background: red; } /* или 0%, 100% */
  25%  {top: 0px; left: 100px; background: blue;}
  50%  {top: 100px; left: 100px; background: yellow;}
  75%  {top: 100px; left: 0px; background: green;}
}&lt;/pre&gt;
  &lt;p id=&quot;194O&quot;&gt;При этом никакой ошибки не будет — мы описываем состояния, их порядок указания лишь вопрос читабельности кода. Если таким образом сгруппировать два состояния, между которыми нет других ключевых кадров, то анимация приостановится на пропорциональное количество времени:&lt;/p&gt;
  &lt;pre id=&quot;eU7X&quot; data-lang=&quot;css&quot;&gt;@keyframes square-move-stop {
  from, to   {top: 0px; left: 0px; background: red;}
  40%, 60%  {top: 0px; left: 100px; background: blue;}
  /* между 40% и 60% нет ключевых кадров - их состояние одинаково */
}&lt;/pre&gt;
  &lt;figure id=&quot;4HmM&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/4a/4e/4a4ef2f2-2c53-4ee6-97e9-e67d2934a590.gif&quot; width=&quot;220&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;k3Uc&quot;&gt;Итак, создали мы крутой набор ключевых кадров, что с ним дальше делать? &lt;/p&gt;
  &lt;p id=&quot;Lxy1&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;c0Ei&quot;&gt;Свойства анимации&lt;/h3&gt;
  &lt;p id=&quot;OebS&quot;&gt;Переходим к свойствам семейства &lt;code&gt;animation&lt;/code&gt;! Они во многом очень похожи на свойства &lt;code&gt;transition&lt;/code&gt; с небольшими дополнениями.&lt;/p&gt;
  &lt;p id=&quot;b5pA&quot;&gt;Первое свойство, собственно, &lt;strong&gt;применяет набор ключевых кадров&lt;/strong&gt; к элементу — это свойство &lt;code&gt;animation-name&lt;/code&gt;. Оно принимает имя заготовленного набора ключевых кадров или, иными словами, вызывает функцию анимации.&lt;/p&gt;
  &lt;p id=&quot;Low2&quot;&gt;Второе свойство, без которого анимация работать не будет, это свойство &lt;strong&gt;длительности анимации&lt;/strong&gt; &lt;code&gt;animation-duration&lt;/code&gt;. Как и его брат-близнец из переходов &lt;code&gt;transition-duration&lt;/code&gt;, принимает числовое значение в секундах &lt;code&gt;s&lt;/code&gt; или миллисекундах &lt;code&gt;ms&lt;/code&gt;.&lt;/p&gt;
  &lt;p id=&quot;ZP8G&quot;&gt;Без этих двух свойств анимация элементарно не применится, они обязательны. Одному элементу можно задать сразу &lt;strong&gt;множество наборов ключевых кадров&lt;/strong&gt;, они указываются в &lt;code&gt;animation-name&lt;/code&gt; через запятую, а все остальные параметры в свойствах, например тот же &lt;code&gt;animation-duration&lt;/code&gt;, сопоставляются по порядку:&lt;/p&gt;
  &lt;pre id=&quot;hSiF&quot; data-lang=&quot;css&quot;&gt;.element {
  animation-name: move, stretch; 
  animation-duration: 2s, 6s; /* 2s длится move, 6s stretch */
}&lt;/pre&gt;
  &lt;p id=&quot;MjZy&quot;&gt;Еще два свойства-родственника из переходов &lt;code&gt;transition&lt;/code&gt; — это &lt;strong&gt;свойство задержки анимации&lt;/strong&gt; &lt;code&gt;animation-delay&lt;/code&gt; и свойство задающее &lt;strong&gt;функцию перехода&lt;/strong&gt;, но уже для всей анимации &lt;code&gt;animation-timing-function&lt;/code&gt;.&lt;/p&gt;
  &lt;p id=&quot;uvf2&quot;&gt;Про задержку, я думаю, и так понятно, с ней, кстати, тоже работают правила множественных значений. Функция перехода тоже работает похожим образом — такие же значения, типа &lt;code&gt;ease&lt;/code&gt;, &lt;code&gt;linear&lt;/code&gt; и т. д., и тоже можно применять функции &lt;code&gt;cubic-bezier()&lt;/code&gt; и &lt;code&gt;steps()&lt;/code&gt;. &lt;/p&gt;
  &lt;p id=&quot;KRMV&quot;&gt;Немного, возможно, не очевидный нюанс — функция перехода заданная в &lt;code&gt;animation-timing-function&lt;/code&gt; применяется ко всем переходам между ключевыми кадрами, а не к прогрессу анимации в целом. То есть каждая анимация между ключевыми кадрами будет по умолчанию &lt;code&gt;ease&lt;/code&gt;.&lt;/p&gt;
  &lt;p id=&quot;YVRV&quot;&gt;Переходим к уникальным для анимации свойствам. Первое такое — свойство &lt;strong&gt;количества итераций&lt;/strong&gt; или проигрывания анимации &lt;code&gt;animation-iteration-count&lt;/code&gt;. Принимает либо число итераций, либо ключевое слово &lt;code&gt;infinite&lt;/code&gt;, обозначающее бесконечное проигрывание анимации.&lt;/p&gt;
  &lt;p id=&quot;z2CF&quot;&gt;Свойство задержки &lt;code&gt;animation-delay&lt;/code&gt;, кстати, применяется только один раз до начала всей анимации, то есть при повторении никакой задержки не будет. Нужно это иметь ввиду, если задержка критична для каждой итерации.&lt;/p&gt;
  &lt;p id=&quot;96xh&quot;&gt;Следующее свойство отвечает за &lt;strong&gt;направление анимации&lt;/strong&gt; &lt;code&gt;animation-direction&lt;/code&gt;. По умолчанию оно «прямое», то есть анимация выполняется от &lt;code&gt;0%&lt;/code&gt; до &lt;code&gt;100%&lt;/code&gt; и свойство имеет значение &lt;code&gt;normal&lt;/code&gt;. Другие же значения:&lt;/p&gt;
  &lt;ul id=&quot;vD86&quot;&gt;
    &lt;li id=&quot;9dM8&quot;&gt;&lt;code&gt;reverse&lt;/code&gt; — «разворачивает» анимацию, она начинает выполняться в обратную сторону — со &lt;code&gt;100%&lt;/code&gt; до &lt;code&gt;0%&lt;/code&gt;, при этом функция перехода НЕ разворачивается.&lt;/li&gt;
    &lt;li id=&quot;CdGd&quot;&gt;&lt;code&gt;alternate&lt;/code&gt; — разворачивает каждую чётную итерацию, таким образом помогает зациклить анимацию без «разрывов» в состояниях элемента.&lt;/li&gt;
    &lt;li id=&quot;hAEi&quot;&gt;&lt;code&gt;alternate-reverse&lt;/code&gt; — разворачивает каждую нечётную итерацию.&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;3jMg&quot;&gt;По умолчанию, после завершения анимации элемент возвращается в своё исходное состояние. Этим, естественно, можно управлять и с помощью комбинаций вышеописанных свойств, но конкретно за это отвечает свойство &lt;code&gt;animation-fill-mode&lt;/code&gt;, которое явно указывает на &lt;strong&gt;состояние элемента после выполнения анимации&lt;/strong&gt;, пусть даже с одной итерацией.&lt;/p&gt;
  &lt;p id=&quot;oQJ4&quot;&gt;Имеет всего четыре значения, включая значение по умолчанию:&lt;/p&gt;
  &lt;ul id=&quot;tYF4&quot;&gt;
    &lt;li id=&quot;4qp6&quot;&gt;&lt;code&gt;none&lt;/code&gt; — по умолчанию, после завершения анимации элемент &lt;em&gt;вернётся в исходное состояние&lt;/em&gt;, которое может отличаться от ключевого кадра &lt;code&gt;0%&lt;/code&gt; или &lt;code&gt;from&lt;/code&gt; — это важно, это не равнозначные состояния.&lt;/li&gt;
    &lt;li id=&quot;a3Rp&quot;&gt;&lt;code&gt;frowards&lt;/code&gt; — после завершения анимации элемент останется в состоянии &lt;em&gt;последнего момента анимации&lt;/em&gt; — это особенно важно при каком-либо значении свойства &lt;code&gt;animation-duration&lt;/code&gt;, т. к. последним состоянием может быть и &lt;code&gt;0%&lt;/code&gt;, если задан &lt;code&gt;reverse&lt;/code&gt; или &lt;code&gt;alternate&lt;/code&gt;.&lt;/li&gt;
    &lt;li id=&quot;j548&quot;&gt;&lt;code&gt;backwards&lt;/code&gt; — наоборот, после завершения анимации элемент примет состояние &lt;em&gt;начального кадра анимации&lt;/em&gt;, который, опять же, может быть не &lt;code&gt;0%&lt;/code&gt; или &lt;code&gt;from&lt;/code&gt;, в зависимости от направления анимации. Это значение имеет еще один эффект — элемент даже до начала анимации принимает состояние указанное в кадре &lt;code&gt;0%&lt;/code&gt;, даже если у анимации есть задержка.&lt;/li&gt;
    &lt;li id=&quot;LnU7&quot;&gt;&lt;code&gt;both&lt;/code&gt; — комбинирует два значения, до начала анимации элемент принимает состояние первого ключевого кадра, а после завершения анимации элемент останется в состоянии последнего момента анимации.&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;BUbQ&quot;&gt;Последнее свойство — это &lt;strong&gt;управление паузой&lt;/strong&gt; или состоянием проигрывания анимации &lt;code&gt;animation-play-state&lt;/code&gt;. Имеет всего два значение — &lt;code&gt;running&lt;/code&gt; по умолчанию и &lt;code&gt;paused&lt;/code&gt;, то бишь — поставить анимацию на паузу. Понятное дело, это свойство-триггер, как например, &lt;code&gt;display: none;&lt;/code&gt;.&lt;/p&gt;
  &lt;p id=&quot;NU0b&quot;&gt;&lt;/p&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;stNM&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;VIRW&quot;&gt;На этом с анимацией всё! Более того, на этом мы, формально, заканчиваем изучение HTML/CSS в тренажёрах! Далее у нас Less, который, конечно, препроцессор CSS, но всё-таки уже не совсем про стили, а скорее про оптимизацию работы с CSS. Потом SVG и после добьем JavaScript.&lt;/p&gt;
  &lt;p id=&quot;QT0W&quot;&gt;Поздравляю себя! :D &lt;/p&gt;
  &lt;p id=&quot;OaKz&quot;&gt;На самом деле я в какой-то момент закопался так, что уже не думал когда закончу, а оно пришло неожиданно. Я уверен, я еще помучаюсь на JavaScript, но в остальном конец уже более-менее ощутим. По крайней мере с вёрсткой.&lt;/p&gt;
  &lt;p id=&quot;jcux&quot;&gt;Спасибо вам за ваше внимание! Продуктивной вам работы!&lt;/p&gt;
  &lt;p id=&quot;bDyc&quot;&gt;Ссылки на мои социальные сети, там анонсы постов, некоторые мои короткие записи, мыслишки и всякое на отвлечённые темы:&lt;/p&gt;
  &lt;section&gt;
    &lt;p id=&quot;TQk6&quot; data-align=&quot;center&quot;&gt;&lt;a href=&quot;https://t.me/arkhelvetios&quot; target=&quot;_blank&quot;&gt;Telegram&lt;/a&gt; — &lt;a href=&quot;https://twitter.com/arkhelvetios&quot; target=&quot;_blank&quot;&gt;Twitter&lt;/a&gt; — &lt;a href=&quot;https://www.instagram.com/arkhelvetios/&quot; target=&quot;_blank&quot;&gt;Instagram&lt;/a&gt; — &lt;a href=&quot;https://www.facebook.com/arkhelvetios&quot; target=&quot;_blank&quot;&gt;Facebook&lt;/a&gt; — &lt;a href=&quot;https://vk.com/arkhelvetios&quot; target=&quot;_blank&quot;&gt;VK&lt;/a&gt;&lt;/p&gt;
  &lt;/section&gt;
  &lt;p id=&quot;FALh&quot;&gt;Заходите куда удобно вам и подписывайтесь! Еще раз спасибо за внимание!&lt;/p&gt;
  &lt;tt-tags id=&quot;hdUH&quot;&gt;
    &lt;tt-tag name=&quot;html&quot;&gt;#html&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;css&quot;&gt;#css&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;html5&quot;&gt;#html5&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;css3&quot;&gt;#css3&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;frontend&quot;&gt;#frontend&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;front_end&quot;&gt;#front_end&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;обучение&quot;&gt;#обучение&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;it&quot;&gt;#it&lt;/tt-tag&gt;
  &lt;/tt-tags&gt;

</content></entry><entry><id>helvetios:css-tricks-part2</id><link rel="alternate" type="text/html" href="https://teletype.in/@helvetios/css-tricks-part2?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=helvetios"></link><title>Сборник тонкостей CSS — оформление текста и CSS-таблицы — Тренажёр HTML Academy</title><published>2022-06-25T00:44:49.927Z</published><updated>2022-06-25T00:44:49.927Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img3.teletype.in/files/e9/02/e902623c-4059-4a8b-8b46-c77a7494c13f.png"></media:thumbnail><category term="webdev" label="Веб-разработка"></category><tt:hashtag>html</tt:hashtag><tt:hashtag>css</tt:hashtag><tt:hashtag>html5</tt:hashtag><tt:hashtag>css3</tt:hashtag><tt:hashtag>frontend</tt:hashtag><tt:hashtag>front_end</tt:hashtag><tt:hashtag>обучение</tt:hashtag><tt:hashtag>it</tt:hashtag><summary type="html">&lt;img src=&quot;https://img2.teletype.in/files/58/96/5896e3c8-a73f-4838-b823-76d1f1bbf804.png&quot;&gt;Продолжаем собирать тонкости, коих осталось не много. В этой статье поговорим об остатках текстовых свойств и о том как работают таблицы, которые изначально и не таблицы вовсе.</summary><content type="html">
  &lt;figure id=&quot;dI5y&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/58/96/5896e3c8-a73f-4838-b823-76d1f1bbf804.png&quot; width=&quot;1200&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;O5Kb&quot;&gt;Продолжаем собирать тонкости, коих осталось не много. В этой статье поговорим об остатках текстовых свойств и о том как работают таблицы, которые изначально и не таблицы вовсе.&lt;/p&gt;
  &lt;p id=&quot;Ze6B&quot;&gt;&lt;/p&gt;
  &lt;nav&gt;
    &lt;ul&gt;
      &lt;li class=&quot;m_level_1&quot;&gt;&lt;a href=&quot;#yb82&quot;&gt;Оформление текста&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_2&quot;&gt;&lt;a href=&quot;#Netr&quot;&gt;Испытания&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_1&quot;&gt;&lt;a href=&quot;#tfFf&quot;&gt;CSS-таблицы&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_2&quot;&gt;&lt;a href=&quot;#Wemh&quot;&gt;Испытания&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/nav&gt;
  &lt;p id=&quot;Rszu&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;yb82&quot;&gt;Оформление текста&lt;/h2&gt;
  &lt;p id=&quot;JwXi&quot;&gt;На самом деле, мало чего интересного осталось. Первым на рассмотрение свойство отвечающее за &lt;strong&gt;падающую тень текста&lt;/strong&gt; &lt;code&gt;text-shadow&lt;/code&gt;. Мы уже разбирали и &lt;a href=&quot;https://blog.arkhelvetios.ru/box-shadow-linear-gradient#jFa8&quot; target=&quot;_blank&quot;&gt;тень блока&lt;/a&gt; &lt;code&gt;box-shadow&lt;/code&gt;, и &lt;a href=&quot;https://blog.arkhelvetios.ru/css-filters-kekstagram#kV1F&quot; target=&quot;_blank&quot;&gt;фильтр падающей тени&lt;/a&gt; &lt;code&gt;drop-shadow()&lt;/code&gt;, и вот, наконец, дошли до тени текста.&lt;/p&gt;
  &lt;p id=&quot;f3CW&quot;&gt;Больше всего работа &lt;code&gt;text-shadow&lt;/code&gt; похожа на фильтр &lt;code&gt;drop-shadow()&lt;/code&gt; — тень повторяет контуры текста и не поддерживает растяжение. Синтаксис записи тоже абсолютно идентичен — первые два значения отвечают за смещение по горизонтали и по вертикали соответственно, третий отвечает за размытие и наконец указывается цвет тени.&lt;/p&gt;
  &lt;pre id=&quot;ZWgo&quot; data-lang=&quot;css&quot;&gt;text-shadow: 5px -5px 0px #333333;&lt;/pre&gt;
  &lt;p id=&quot;TAHh&quot;&gt;Далее в части вспоминаем про &lt;strong&gt;подключение шрифтов&lt;/strong&gt; через &lt;code&gt;@font-face&lt;/code&gt;, которое &lt;a href=&quot;https://blog.arkhelvetios.ru/advanced-html-css-part1#IrZx&quot; target=&quot;_blank&quot;&gt;мы разбирали&lt;/a&gt; в начале «среднего уровня» тренажёров. Правда, здесь нам показали, что за «шрифт» можно выдать набор SVG фигур, как бы, упакованных в шрифтовой формат. Я такое даже пару раз видел во время работы и насколько знаю, многие конструкторы примерно так и загружают свои «библиотеки иконок».&lt;/p&gt;
  &lt;p id=&quot;IkYs&quot;&gt;Следующее свойство &lt;code&gt;letter-spacing&lt;/code&gt; отвечающее за &lt;strong&gt;расстояние между символами&lt;/strong&gt;. Принимает числовое значение — положительные увеличивают расстояние между символами, отрицательные уменьшают. По умолчанию равно нулю — базовое расстояние между символами.&lt;/p&gt;
  &lt;p id=&quot;OOQT&quot;&gt;По умолчанию, перенос строки происходит только по словам, но с помощью свойства &lt;code&gt;overflow-wrap&lt;/code&gt; или его альтернативной записью, как написано в тренажёре, &lt;code&gt;word-wrap&lt;/code&gt; — можно задать &lt;strong&gt;перенос по символам&lt;/strong&gt; используя значение &lt;code&gt;break-word&lt;/code&gt; — «ломать слово». По умолчанию же значение &lt;code&gt;normal&lt;/code&gt;.&lt;/p&gt;
  &lt;p id=&quot;p9do&quot;&gt;Очень специфичное свойство &lt;code&gt;text-overflow&lt;/code&gt;, отвечающее за то, как будет выглядеть текст в конце непереносимой строки, например, очень длинное слово не поместилось, а &lt;code&gt;overflow-wrap: normal;&lt;/code&gt;. По умолчанию имеет значение &lt;code&gt;clip&lt;/code&gt; — текст просто обрезается, но можно задать значение &lt;code&gt;ellipsis&lt;/code&gt; и придать более красивый вид — слово обрежется раньше, но в конце строки появится многоточие.&lt;/p&gt;
  &lt;figure id=&quot;2bCL&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/5d/d0/5dd0e325-6321-4181-9936-1fd53538f722.png&quot; width=&quot;729&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;U5Om&quot;&gt;Далее, на мой взгляд, немного архаичное свойство &lt;code&gt;text-indent&lt;/code&gt;, отвечающее за &lt;strong&gt;смещение начала первой строки абзаца&lt;/strong&gt;. Та самая «красная строка» задаётся через это свойство. Мы его &lt;a href=&quot;https://blog.arkhelvetios.ru/workshop-academy#NzrI&quot; target=&quot;_blank&quot;&gt;уже использовали&lt;/a&gt;, правда в других целях — задавали значение &lt;code&gt;-1000px&lt;/code&gt;, чтобы скрыть текст над спрайтами.&lt;/p&gt;
  &lt;p id=&quot;Ydxv&quot;&gt;Пару уроков отведено псевдоэлементам &lt;code&gt;::first-letter&lt;/code&gt; и &lt;code&gt;::first-line&lt;/code&gt;, которые мы уже &lt;a href=&quot;https://blog.arkhelvetios.ru/advanced-html-css-part2#bhP8&quot; target=&quot;_blank&quot;&gt;немного разбирали&lt;/a&gt; в части про селекторы. Лишним не будет, кончено, но на мой взгляд они тоже малоприменимы.&lt;/p&gt;
  &lt;p id=&quot;4xWX&quot;&gt;А вот что интересно, так это семейство свойств отвечающих за &lt;strong&gt;многоколоночную вёрстку текста&lt;/strong&gt; и первое из них &lt;code&gt;column-count&lt;/code&gt; отвечает за &lt;strong&gt;количество столбцов&lt;/strong&gt; на которое нужно разделить текст. Выглядит это как журнальная или газетная вёрстка — длинный текст разделяется на какое-то количество столбцов, это упрощает чтение на большом листе. &lt;/p&gt;
  &lt;p id=&quot;fgd9&quot;&gt;Свойство &lt;code&gt;column-count&lt;/code&gt; принимает числовое значение этих столбцов и текстовый блок автоматически разделяется на них. Честно признаюсь, я какое-то время делал это все отдельным текстовыми блоками во флекс-контейнере!&lt;/p&gt;
  &lt;p id=&quot;YXfj&quot;&gt;Другой вариант задать не число колонок, а &lt;strong&gt;минимальную ширину колонки&lt;/strong&gt; с помощью свойства &lt;code&gt;column-width&lt;/code&gt; — браузер автоматически разделит текст на максимально доступное количество колонок указанной ширины.&lt;/p&gt;
  &lt;p id=&quot;0jQ0&quot;&gt;Последнее свойство из семейства — &lt;code&gt;column-gap&lt;/code&gt;, отвечающее за &lt;strong&gt;расстояние между колонками&lt;/strong&gt;. По умолчанию имеет значение &lt;code&gt;1em&lt;/code&gt;, но можно задать любое в пикселях, пунктах и других абсолютных единицах.&lt;/p&gt;
  &lt;p id=&quot;gQk2&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;Netr&quot;&gt;Испытания&lt;/h3&gt;
  &lt;p id=&quot;rk96&quot;&gt;Испытаний целых три штуки и все крайне простые. С текстом особо ничего, видимо, не придумать. Первое испытание на тени:&lt;/p&gt;
  &lt;figure id=&quot;wRYi&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://sun9-85.userapi.com/impg/QCphIp3hxFcSX6LuCfJ-G-dqYFP0X-z0Lv1L2w/8mE661yohBU.jpg?size=1318x921&amp;quality=96&amp;sign=f76e973591f73bcb1e009dc4629f8d3a&amp;type=album&quot; width=&quot;1318&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;HQrn&quot;&gt;Второе испытание тоже на тени и, по моему, еще легче первого. Здесь только ловушка небольшая с текстом снизу и подобрать пиксели для смайликов.&lt;/p&gt;
  &lt;figure id=&quot;i6dc&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://sun9-54.userapi.com/impg/OuT1QN4R-4IjCFbZoxM9uo2wB504MuCdoC9BBg/P9dwxTiXf6g.jpg?size=1321x922&amp;quality=96&amp;sign=0580582bae9eddecdc9aef351fd5fd59&amp;type=album&quot; width=&quot;1321&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;36IX&quot;&gt;Третье испытание тоже лёгкое — сделать из текста логотип, используя свойство overflow-wrap и парочку других из пройдённой части.&lt;/p&gt;
  &lt;figure id=&quot;3uzD&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://sun9-21.userapi.com/impg/_RPzd-en2XD9qN4A0N7olR-UH9wMFYKgwXvtaQ/-DhXk468rGE.jpg?size=1319x920&amp;quality=96&amp;sign=db63e9f14d1d78b575e7be3dfb0245f9&amp;type=album&quot; width=&quot;1319&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;IkWJ&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;tfFf&quot;&gt;CSS-таблицы&lt;/h2&gt;
  &lt;p id=&quot;JZwH&quot;&gt;Честно говоря, меня немного разочаровала истина — я думал, таблицы на CSS будут как-то принципиально отличаться от таблиц в HTML, но по сути нет. Хрен знает чего я вообще ждал, сам не понимаю, но я себе каким-то образом завысил ожидания.&lt;/p&gt;
  &lt;p id=&quot;3Rfo&quot;&gt;Таблицы на CSS это когда не табличным элементам мы задаём табличное поведение через свойство &lt;code&gt;display&lt;/code&gt;. Формально, практически любую структуру можно завернуть в таблицу.&lt;/p&gt;
  &lt;p id=&quot;SPde&quot;&gt;У меня сразу же появились вопросы:&lt;/p&gt;
  &lt;ol id=&quot;his9&quot;&gt;
    &lt;li id=&quot;jkF6&quot;&gt;А в чем смысл? Почему не сверстать заранее таблицу в HTML если она нужна? Количество символов будет примерно таким же.&lt;/li&gt;
    &lt;li id=&quot;3I9a&quot;&gt;Что по поводу семантики? Дерево div’ов с табличными свойствами лучше чем табличные теги? Как к этому относятся поисковики?&lt;/li&gt;
    &lt;li id=&quot;bvBd&quot;&gt;Зачем вообще был придуман этот велосипед?&lt;/li&gt;
  &lt;/ol&gt;
  &lt;p id=&quot;V92q&quot;&gt;Частично я сам себе отвечу — чтобы перенести все построения в CSS и управлять из одного места свойствами типа &lt;code&gt;colspan&lt;/code&gt; и подобными. Но вот вопрос про семантику открытый.&lt;/p&gt;
  &lt;p id=&quot;EzO7&quot;&gt;В остальном, можно описать CSS таблицы так — каждому табличному тегу есть свой аналог в виде значения свойства &lt;code&gt;display&lt;/code&gt;. Первую половину части мы просто рассматриваем каждый вариант отдельно строя таким образом таблицу.&lt;/p&gt;
  &lt;ul id=&quot;qYUu&quot;&gt;
    &lt;li id=&quot;75b8&quot;&gt;&lt;code&gt;display: table;&lt;/code&gt; — аналогичен тегу &lt;code&gt;&amp;lt;table&amp;gt;&lt;/code&gt;, обозначающий таблицу;&lt;/li&gt;
    &lt;li id=&quot;IZcz&quot;&gt;&lt;code&gt;display: table-row;&lt;/code&gt; — аналогичен тегу &lt;code&gt;&amp;lt;tr&amp;gt;&lt;/code&gt;, строка таблицы;&lt;/li&gt;
    &lt;li id=&quot;2gb6&quot;&gt;&lt;code&gt;display: table-cell;&lt;/code&gt; — аналогичен тегу &lt;code&gt;&amp;lt;td&amp;gt;&lt;/code&gt;, ячейка таблицы;&lt;/li&gt;
    &lt;li id=&quot;W5z0&quot;&gt;&lt;code&gt;display: table-caption;&lt;/code&gt; — аналогичен тегу &lt;code&gt;&amp;lt;caption&amp;gt;&lt;/code&gt;, заголовок таблицы;&lt;/li&gt;
    &lt;li id=&quot;kABg&quot;&gt;&lt;code&gt;display: table-header-group;&lt;/code&gt; — аналогичен &lt;code&gt;&amp;lt;thead&amp;gt;&lt;/code&gt;, группа строк шапки;&lt;/li&gt;
    &lt;li id=&quot;z3LZ&quot;&gt;&lt;code&gt;display: table-footer-group;&lt;/code&gt; — аналогичен &lt;code&gt;&amp;lt;tfoot&amp;gt;&lt;/code&gt;, группа строк нижней части таблицы;&lt;/li&gt;
    &lt;li id=&quot;FAQm&quot;&gt;&lt;code&gt;display: table-row-group;&lt;/code&gt; — аналогичен &lt;code&gt;&amp;lt;tbody&amp;gt;&lt;/code&gt;, просто группа строк;&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;xOG7&quot;&gt;Дальше идут два тега, про которые я впервые увидел в этой части, поэтому про них поговорим отдельно. Оказывается, можно задавать размер столбцов не через ячейку, а сразу всему столбцу.&lt;/p&gt;
  &lt;p id=&quot;HXQX&quot;&gt;В HTML для этого есть одиночный тег &lt;code&gt;&amp;lt;col&amp;gt;&lt;/code&gt;, который указывается в самом начале сразу после тега &lt;code&gt;&amp;lt;table&amp;gt;&lt;/code&gt; и каждый такой тег отвечает за столбец. Им можно задать атрибут &lt;code&gt;width&lt;/code&gt;, который и будет влиять на всю таблицу, точнее на все ячейки в этом столбце.&lt;/p&gt;
  &lt;pre id=&quot;vEn6&quot; data-lang=&quot;html&quot;&gt;&amp;lt;table&amp;gt;
  &amp;lt;col width=&amp;quot;20%&amp;quot;&amp;gt; &amp;lt;!-- Первый столбец – ячейки 1.1 и 1.2 --&amp;gt;
  &amp;lt;col width=&amp;quot;80%&amp;quot;&amp;gt; &amp;lt;!-- Второй столбец – ячейки 2.1 и 2.2 --&amp;gt;
  &amp;lt;tr&amp;gt;
    &amp;lt;td&amp;gt;1.1&amp;lt;/td&amp;gt; &amp;lt;td&amp;gt;2.1&amp;lt;/td&amp;gt;
  &amp;lt;/tr&amp;gt;
  &amp;lt;tr&amp;gt;
    &amp;lt;td&amp;gt;1.2&amp;lt;/td&amp;gt; &amp;lt;td&amp;gt;2.2&amp;lt;/td&amp;gt;
  &amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;&lt;/pre&gt;
  &lt;p id=&quot;Hvcn&quot;&gt;Столбцы можно группировать с помощью тега &lt;code&gt;&amp;lt;colgroup&amp;gt;&lt;/code&gt;, которой тоже можно задать атрибут &lt;code&gt;width&lt;/code&gt;, а все &lt;code&gt;&amp;lt;col&amp;gt;&lt;/code&gt; внутри этого тега получат равные доли ширины.&lt;/p&gt;
  &lt;p id=&quot;gGPg&quot;&gt;Так вот, в CSS таблицах есть аналоги и этим тегам:&lt;/p&gt;
  &lt;ul id=&quot;fxB4&quot;&gt;
    &lt;li id=&quot;RKg9&quot;&gt;&lt;code&gt;display: table-column;&lt;/code&gt; — аналогичен &lt;code&gt;&amp;lt;col&amp;gt;&lt;/code&gt;;&lt;/li&gt;
    &lt;li id=&quot;eWzP&quot;&gt;&lt;code&gt;display: table-column-group;&lt;/code&gt; — аналогичен &lt;code&gt;&amp;lt;colgroup&amp;gt;&lt;/code&gt;;&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;IGSe&quot;&gt;Все табличные свойства при этом начинают работать, включая специфичные для таблиц типа &lt;code&gt;border-collapse&lt;/code&gt; и &lt;code&gt;border-spacing&lt;/code&gt;. То есть дальнейшая стилизация идет как с обычной таблице.&lt;/p&gt;
  &lt;p id=&quot;YdvU&quot;&gt;Кстати один урок в части посвящен тому, что таблицу можно сделать блочно-строчной с помощью значение &lt;code&gt;inline-table&lt;/code&gt;. Понятия не имею где это можно применить, но даже такое можно сделать.&lt;/p&gt;
  &lt;p id=&quot;KtD6&quot;&gt;Еще отдельно отмечу то как оформлена часть, она мне напомнила часть про двумерные трансформации — явный реверанс в сторону РПГ или ДНД, тут мы тоже собираем инвентарь. Кажется мелочью, а даже такую пресную информацию делает увлекательной! Мое уважение составителю!&lt;/p&gt;
  &lt;p id=&quot;r0RN&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;Wemh&quot;&gt;Испытания&lt;/h3&gt;
  &lt;p id=&quot;kvTZ&quot;&gt;На них придётся чутка посидеть, они не то чтобы сложные, но в голове кирпичики сложить придётся, чтобы понять чего и куда. В первом заблокирован HTML и только с помощью CSS надо превратить список в таблицу:&lt;/p&gt;
  &lt;figure id=&quot;TPuK&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://sun9-33.userapi.com/impg/_RpeGlOkogpWad-OlVyGwjoMah-AGBAW3H2HVQ/3qGo09UXKug.jpg?size=1319x921&amp;quality=96&amp;sign=45484e8f55099d1c2124ffc2826a03d4&amp;type=album&quot; width=&quot;1319&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;DlVb&quot;&gt;Второе испытание на табличные свойства и работу с рамками и отступами в таблице, плюс вспоминаем псевдоклассы:&lt;/p&gt;
  &lt;figure id=&quot;WzGZ&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://sun9-77.userapi.com/impg/YNJ28ki1px2FMuQLMsXK-3l9Qic6dQk8KSAr2g/YYuOeW70pwE.jpg?size=1319x923&amp;quality=96&amp;sign=220679c49e3d3d7951a2d71bc0eab11c&amp;type=album&quot; width=&quot;1319&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;9781&quot;&gt;&lt;/p&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;Gvbr&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;VbR8&quot;&gt;Так и знал, что получится такой, можно сказать, огрызок от первой части про тонкости. Но да ладно, это лучше чем лонгрид на миллиард символов. Надо охлаждать свое графоманство.&lt;/p&gt;
  &lt;p id=&quot;LxwD&quot;&gt;Вам огромное спасибо за ваше внимание! Увлекательного вам обучения!&lt;/p&gt;
  &lt;p id=&quot;jArj&quot;&gt;Ссылки на мои социальные сети, там анонсы постов, некоторые мои короткие записи, мыслишки и всякое на отвлечённые темы:&lt;/p&gt;
  &lt;section style=&quot;background-color:hsl(hsl(263, 48%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;kDzq&quot; data-align=&quot;center&quot;&gt;&lt;a href=&quot;https://t.me/arkhelvetios&quot; target=&quot;_blank&quot;&gt;Telegram&lt;/a&gt; — &lt;a href=&quot;https://twitter.com/arkhelvetios&quot; target=&quot;_blank&quot;&gt;Twitter&lt;/a&gt; — &lt;a href=&quot;https://www.instagram.com/arkhelvetios/&quot; target=&quot;_blank&quot;&gt;Instagram&lt;/a&gt; — &lt;a href=&quot;https://www.facebook.com/arkhelvetios&quot; target=&quot;_blank&quot;&gt;Facebook&lt;/a&gt; — &lt;a href=&quot;https://vk.com/arkhelvetios&quot; target=&quot;_blank&quot;&gt;VK&lt;/a&gt;&lt;/p&gt;
  &lt;/section&gt;
  &lt;p id=&quot;6QCd&quot;&gt;Заходите куда удобно вам и подписывайтесь! Еще раз спасибо за внимание!&lt;/p&gt;
  &lt;tt-tags id=&quot;P420&quot;&gt;
    &lt;tt-tag name=&quot;html&quot;&gt;#html&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;css&quot;&gt;#css&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;html5&quot;&gt;#html5&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;css3&quot;&gt;#css3&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;frontend&quot;&gt;#frontend&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;front_end&quot;&gt;#front_end&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;обучение&quot;&gt;#обучение&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;it&quot;&gt;#it&lt;/tt-tag&gt;
  &lt;/tt-tags&gt;

</content></entry><entry><id>helvetios:css-tricks-part1</id><link rel="alternate" type="text/html" href="https://teletype.in/@helvetios/css-tricks-part1?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=helvetios"></link><title>Сборник тонкостей CSS — селекторы, фоны и рамки — Тренажёр HTML Academy</title><published>2022-06-24T19:41:38.501Z</published><updated>2022-06-24T19:41:38.501Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img1.teletype.in/files/01/c1/01c1cfe3-c919-4ffd-acf7-ba8a95c54c5c.png"></media:thumbnail><category term="webdev" label="Веб-разработка"></category><tt:hashtag>html</tt:hashtag><tt:hashtag>css</tt:hashtag><tt:hashtag>html5</tt:hashtag><tt:hashtag>css3</tt:hashtag><tt:hashtag>frontend</tt:hashtag><tt:hashtag>front_end</tt:hashtag><tt:hashtag>обучение</tt:hashtag><tt:hashtag>it</tt:hashtag><summary type="html">&lt;img src=&quot;https://img2.teletype.in/files/d1/35/d135546e-551b-44fc-aaf1-6a7c6d7d9571.png&quot;&gt;Перескочим на «продвинутый» уровень тренажёров. Под «тонкостями» в тренажёрах имеются ввиду несколько дополнительных частей к уже пройденным — более сложные селекторы, специфичные свойства рамок, фонов и текста. А еще изучим построение таблиц на CSS.</summary><content type="html">
  &lt;figure id=&quot;kgeS&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/d1/35/d135546e-551b-44fc-aaf1-6a7c6d7d9571.png&quot; width=&quot;1200&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;ivri&quot;&gt;Перескочим на «продвинутый» уровень тренажёров. Под «тонкостями» в тренажёрах имеются ввиду несколько дополнительных частей к уже пройденным — более сложные селекторы, специфичные свойства рамок, фонов и текста. А еще изучим построение таблиц на CSS.&lt;/p&gt;
  &lt;p id=&quot;HWTU&quot;&gt;Перескакиваю я потому, что в среднем остался только JavaScript и еще блок про SVG. Я подумал, раз после определённого момента порядок блоков уже условный, то лучше доучить остатки CSS из продвинутого уровня, а потом уже браться за JS и остальное и потом плавно перейдём уже на курсы.&lt;/p&gt;
  &lt;p id=&quot;u1FP&quot;&gt;&lt;/p&gt;
  &lt;nav&gt;
    &lt;ul&gt;
      &lt;li class=&quot;m_level_1&quot;&gt;&lt;a href=&quot;#JF5h&quot;&gt;Селекторы&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_2&quot;&gt;&lt;a href=&quot;#WfYc&quot;&gt;Продвинутый селектор по атрибуту&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_2&quot;&gt;&lt;a href=&quot;#H6nN&quot;&gt;Больше псевдоклассов&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_2&quot;&gt;&lt;a href=&quot;#ZMRh&quot;&gt;Испытание&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_1&quot;&gt;&lt;a href=&quot;#lH01&quot;&gt;Рамки и фоны&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_2&quot;&gt;&lt;a href=&quot;#Mc4U&quot;&gt;Фоны&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_2&quot;&gt;&lt;a href=&quot;#7sGa&quot;&gt;Рамки&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_2&quot;&gt;&lt;a href=&quot;#uArk&quot;&gt;Фигуры из рамок&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_2&quot;&gt;&lt;a href=&quot;#lk0n&quot;&gt;Испытания&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/nav&gt;
  &lt;p id=&quot;EqsH&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;JF5h&quot;&gt;Селекторы&lt;/h2&gt;
  &lt;p id=&quot;0bfF&quot;&gt;Мы уже забегали в эту часть когда проходили &lt;a href=&quot;https://blog.arkhelvetios.ru/advance-workshop-academy#5DXr&quot; target=&quot;_blank&quot;&gt;Мастерские&lt;/a&gt; и делали слайдер на чистом CSS. Точнее, на неё там активно ссылались. Итак, в этой части мы доучим селекторы по атрибутам и специфичные, интересные псевдоклассы.&lt;/p&gt;
  &lt;p id=&quot;6Da2&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;WfYc&quot;&gt;Продвинутый селектор по атрибуту&lt;/h3&gt;
  &lt;p id=&quot;04bS&quot;&gt;Итак, про &lt;a href=&quot;https://blog.arkhelvetios.ru/advanced-html-css-part2#JgQG&quot; target=&quot;_blank&quot;&gt;селекторы по атрибуту&lt;/a&gt; мы уже знаем из прошлых частей, выглядит он как тег с указанием атрибута и его значением:&lt;/p&gt;
  &lt;pre id=&quot;cot1&quot; data-lang=&quot;css&quot;&gt;input[type=&amp;quot;text&amp;quot;] {...} /* все input с type=&amp;quot;text&amp;quot; */&lt;/pre&gt;
  &lt;p id=&quot;VJwX&quot;&gt;У этого вида селекторов есть дополнительные механизмы поиска элементов — перед знаком равно &lt;code&gt;=&lt;/code&gt; добавляется модификатор для поиска «подстроки», то есть части строки в значении. Модификаторов несколько и насколько я понял, все они взяты из &lt;a href=&quot;https://ru.wikipedia.org/wiki/%D0%A0%D0%B5%D0%B3%D1%83%D0%BB%D1%8F%D1%80%D0%BD%D1%8B%D0%B5_%D0%B2%D1%8B%D1%80%D0%B0%D0%B6%D0%B5%D0%BD%D0%B8%D1%8F#%D0%9F%D0%BE%D0%B7%D0%B8%D1%86%D0%B8%D1%8F_%D0%B2%D0%BD%D1%83%D1%82%D1%80%D0%B8_%D1%81%D1%82%D1%80%D0%BE%D0%BA%D0%B8&quot; target=&quot;_blank&quot;&gt;регулярных выражений&lt;/a&gt; и работают аналогичным образом.&lt;/p&gt;
  &lt;ul id=&quot;wsxl&quot;&gt;
    &lt;li id=&quot;v8Dr&quot;&gt;&lt;strong&gt;Начало строки&lt;/strong&gt; &lt;code&gt;[attr^=&amp;quot;value&amp;quot;]&lt;/code&gt; — символ &lt;code&gt;^&lt;/code&gt; указывает на поиск всех элементов с атрибутом &lt;code&gt;attr&lt;/code&gt; со значением начинающегося на &lt;code&gt;value&lt;/code&gt;. Под это подойдет, например &lt;code&gt;value-1&lt;/code&gt;, &lt;code&gt;valueone&lt;/code&gt;, &lt;code&gt;value__top&lt;/code&gt; и т. д.&lt;/li&gt;
    &lt;li id=&quot;UMIh&quot;&gt;&lt;strong&gt;Конец строки&lt;/strong&gt; &lt;code&gt;[attr$=&amp;quot;value&amp;quot;]&lt;/code&gt; — символ &lt;code&gt;$&lt;/code&gt; указывает на поиск всех элементов с атрибутом &lt;code&gt;attr&lt;/code&gt; со значением заканчивающимся на &lt;code&gt;value&lt;/code&gt;. Подойдёт, например, &lt;code&gt;header-value&lt;/code&gt;, &lt;code&gt;notvalue&lt;/code&gt;, &lt;code&gt;file.value&lt;/code&gt; и т. д.&lt;/li&gt;
    &lt;li id=&quot;4t4E&quot;&gt;&lt;strong&gt;Содержит в строке&lt;/strong&gt; &lt;code&gt;[attr*=&amp;quot;value&amp;quot;]&lt;/code&gt; — символ &lt;code&gt;*&lt;/code&gt; указывает на поиск всех элементов с атрибутом &lt;code&gt;attr&lt;/code&gt; со значением содержащим &lt;code&gt;value&lt;/code&gt; в любом месте строки атрибута. Подойдет &lt;code&gt;textvalue1&lt;/code&gt;, &lt;code&gt;shop value rub&lt;/code&gt;, &lt;code&gt;text__extd value&lt;/code&gt;, в общем любые совпадения.&lt;/li&gt;
    &lt;li id=&quot;4wIF&quot;&gt;&lt;strong&gt;Содержит слово в строке&lt;/strong&gt; &lt;code&gt;[attr~=&amp;quot;value&amp;quot;]&lt;/code&gt; — символ &lt;code&gt;~&lt;/code&gt; работает подобно &lt;code&gt;*&lt;/code&gt;, но теперь ищет именно слово отдельно, то есть разделённое с обеих сторон либо пробелом, либо переносом строки. Подойдет &lt;code&gt;shop value rub&lt;/code&gt;, но уже не подойдет &lt;code&gt;textvalue1&lt;/code&gt;.&lt;/li&gt;
    &lt;li id=&quot;Zo1I&quot;&gt;&lt;strong&gt;Содержит префикс&lt;/strong&gt; &lt;code&gt;[attr|=&amp;quot;value&amp;quot;]&lt;/code&gt; — под префиксом имеется ввиду значение вида &lt;code&gt;value-&lt;/code&gt; — именно с дефисом в конце, то есть частный, но распространённый случай начала строки. Также этот селектор посчитает за корректный для себя значение &lt;code&gt;value&lt;/code&gt; — то есть одно целое слово.&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;ZIYo&quot;&gt;Эти селекторы мне бы очень пригодились в свое время для настройки Google Tag Manager’а, когда надо было прицепиться к каким-нибудь хитро сделанным полям в каком-нибудь конструкторе.&lt;/p&gt;
  &lt;p id=&quot;Q5kk&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;H6nN&quot;&gt;Больше псевдоклассов&lt;/h3&gt;
  &lt;p id=&quot;B1gI&quot;&gt;Часть из представленных здесь псевдоклассов мы уже тоже встречали, большинство из них работают с булевыми атрибутами типа &lt;code&gt;checked&lt;/code&gt; и им подобными для полей форм.&lt;/p&gt;
  &lt;ul id=&quot;8L5R&quot;&gt;
    &lt;li id=&quot;OUSU&quot;&gt;Псевдоклассы &lt;code&gt;:disabled&lt;/code&gt; и &lt;code&gt;:enabled&lt;/code&gt; — обращаются к элементам, чаще всего полям, с одноимённым атрибутом &lt;code&gt;disabled&lt;/code&gt; или без него соответственно.&lt;/li&gt;
    &lt;li id=&quot;w3RD&quot;&gt;Псевдоклассы &lt;code&gt;:required&lt;/code&gt; и &lt;code&gt;:optional&lt;/code&gt; — обращаются к элементам, которым проставлен и, соответственно, не проставлен атрибут &lt;code&gt;required&lt;/code&gt; — поле обязательно к заполнению.&lt;/li&gt;
    &lt;li id=&quot;gqMn&quot;&gt;Псевдоклассы &lt;code&gt;:read-only&lt;/code&gt; и &lt;code&gt;:read-write&lt;/code&gt; — аналогично, обращается к элементам, которым проставлен атрибут &lt;code&gt;readonly&lt;/code&gt; и которым он не проставлен. Нам в тренажёре напоминают, что &lt;code&gt;disabled&lt;/code&gt; визуально и функционально похож, но суть и селектор у него другой.&lt;/li&gt;
    &lt;li id=&quot;frS0&quot;&gt;Псевдокласс &lt;code&gt;:checked&lt;/code&gt; — обращается к элементам типа radio или checkbox, которые в данный момент выбраны.&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;Yhw3&quot;&gt;И отдельно можно выделить псевдоклассы которые работают, можно сказать, с корректностью информации вводимой в поля. Как мы &lt;a href=&quot;https://blog.arkhelvetios.ru/advanced-html-css-part1#2uam&quot; target=&quot;_blank&quot;&gt;уже знаем&lt;/a&gt;, у некоторых типов полей, например, у &lt;code&gt;email&lt;/code&gt; или &lt;code&gt;url&lt;/code&gt;, есть автоматическая валидация введённых данных, а большинству остальных — область допустимых значений можно задать отдельно через атрибут &lt;code&gt;pattern=&amp;quot;&amp;quot;&lt;/code&gt;.&lt;/p&gt;
  &lt;ul id=&quot;kJdL&quot;&gt;
    &lt;li id=&quot;FOvf&quot;&gt;Псевдокласс &lt;code&gt;:valid&lt;/code&gt; — обращается ко всем элементам, у которых введённое значение попадает под требования.&lt;/li&gt;
    &lt;li id=&quot;IkUs&quot;&gt;Псевдокласс &lt;code&gt;:invalid&lt;/code&gt; — напротив, обращается ко всем элементам, у которых введённое значение некорректно и не попадает под требования.&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;QFOQ&quot;&gt;Для типов полей, где задан диапазон допустимых значений &lt;code&gt;min&lt;/code&gt; и &lt;code&gt;max&lt;/code&gt; — это например, &lt;code&gt;number&lt;/code&gt; и, возможно, &lt;code&gt;range&lt;/code&gt;, есть специальные псевдоклассы проверяющие именно попадание в диапазон.&lt;/p&gt;
  &lt;ul id=&quot;W16I&quot;&gt;
    &lt;li id=&quot;erE4&quot;&gt;Псевдокласс &lt;code&gt;:in-range&lt;/code&gt; — обращается ко всем элементам, значение которых попадает в диапазон&lt;/li&gt;
    &lt;li id=&quot;O2mw&quot;&gt;Псевдокласс &lt;code&gt;:out-of-range&lt;/code&gt; — выбирает все элементы, значение которых за пределами диапазона.&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;UmhN&quot;&gt;Именно в конце этой части нам показывают чудеса с &lt;code&gt;checked&lt;/code&gt; и селектором &lt;code&gt;~&lt;/code&gt;, правда здесь мы просто скрываем блоки. Надо будет что-нибудь интересное с этим сделать.&lt;/p&gt;
  &lt;p id=&quot;j8dh&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;ZMRh&quot;&gt;Испытание&lt;/h3&gt;
  &lt;p id=&quot;dbiC&quot;&gt;Всего одно испытание с уже знакомой формой. В этот раз играемся с атрибутными селекторами. Всё уже сверстано, нам надо только подобрать правильные селекторы.&lt;/p&gt;
  &lt;figure id=&quot;mNcc&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://sun9-49.userapi.com/impg/iXGKNgjEIJlbFeQci_VGgxiXE-GcWZbE7bCdUw/ogSskjJySiE.jpg?size=1321x923&amp;quality=96&amp;sign=1fbf40f7551926fe85e54fd254c99f07&amp;type=album&quot; width=&quot;1321&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;reax&quot;&gt;Задача не сложная, может возникнуть затык с декоративными чекбоксами и радиокнопками — это псевдоэлементы, а сами переключатели скрыты.&lt;/p&gt;
  &lt;p id=&quot;Tgyw&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;lH01&quot;&gt;Рамки и фоны&lt;/h2&gt;
  &lt;p id=&quot;fkdj&quot;&gt;Касаемо фонов — большую часть из указанного здесь мы уже видели и даже использовали. А вот с рамками, оказывается, можно делать очень интересные штуки!&lt;/p&gt;
  &lt;p id=&quot;HpUj&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;Mc4U&quot;&gt;Фоны&lt;/h3&gt;
  &lt;p id=&quot;Sugh&quot;&gt;Сначала разберёмся окончательно с фонами. Первым на очереди у нас свойство отвечающее за &lt;strong&gt;размер фонового изображения&lt;/strong&gt; &lt;code&gt;background-size&lt;/code&gt;. Да, мы уже его использовали пару раз, он даже был задействован в &lt;a href=&quot;https://blog.arkhelvetios.ru/keksby&quot; target=&quot;_blank&quot;&gt;Кексби&lt;/a&gt;, будь он неладен.&lt;/p&gt;
  &lt;p id=&quot;8aaZ&quot;&gt;Это свойство принимает два типа значений — численные в &lt;code&gt;px&lt;/code&gt; или &lt;code&gt;%&lt;/code&gt;, которые явно обозначают ширину и высоту фонового изображения, и ключевые слова:&lt;/p&gt;
  &lt;ul id=&quot;BMqH&quot;&gt;
    &lt;li id=&quot;maLe&quot;&gt;&lt;code&gt;auto&lt;/code&gt; — значение по умолчанию для ширины и высоты.&lt;/li&gt;
    &lt;li id=&quot;Sbmx&quot;&gt;&lt;code&gt;contain&lt;/code&gt; — изображение полностью умещается в блок по большей стороне, сохраняя свои пропорции, таким образом фоновое изображение может закрывать не всё пространство блока, если их размеры и пропорции не совпадают.&lt;/li&gt;
    &lt;li id=&quot;rGdm&quot;&gt;&lt;code&gt;cover&lt;/code&gt; — изображение полностью закрывает пространство блока, сохраняя при этом свои пропорции, части изображения не поместившиеся в блок — обрезаются.&lt;/li&gt;
  &lt;/ul&gt;
  &lt;figure id=&quot;wzeP&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/7d/ec/7dec7762-12f1-4295-a8d2-ac383b093011.png&quot; width=&quot;663&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;ERNd&quot;&gt;Следующее свойство &lt;code&gt;background-origin&lt;/code&gt; отвечает за то &lt;strong&gt;в каких границах&lt;/strong&gt; будет отображаться фоновое изображение:&lt;/p&gt;
  &lt;ul id=&quot;r8YH&quot;&gt;
    &lt;li id=&quot;cS49&quot;&gt;&lt;code&gt;content-box&lt;/code&gt; — отображается только в области содержимого, то есть не отображается даже на внутренних отступах.&lt;/li&gt;
    &lt;li id=&quot;QE8W&quot;&gt;&lt;code&gt;padding-box&lt;/code&gt; — значение по умолчанию, отображается во внутренней области бокса, исключая рамки и внешние отступы.&lt;/li&gt;
    &lt;li id=&quot;lx5p&quot;&gt;&lt;code&gt;border-box&lt;/code&gt; — в отображение включаются рамки, даже если они непрозрачны, то есть изображение будет залезать под них.&lt;/li&gt;
  &lt;/ul&gt;
  &lt;figure id=&quot;ao1d&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://htmlacademy.ru/assets/courses/88/img/box-sizing.jpg&quot; width=&quot;461&quot; /&gt;
    &lt;figcaption&gt;margin-box, видимо, не завезли.&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;Zxgp&quot;&gt;Его сосед по парте — свойство &lt;code&gt;background-clip&lt;/code&gt;, которое отвечает &lt;strong&gt;за обрезку всего фона&lt;/strong&gt; — и изображения, и цвета. Имеет абсолютно такие же значения и работает по тому же принципу, но отвечает за то в какой области будет видно, а не то на какую область растянуто. По умолчанию стоит значение &lt;code&gt;border-box&lt;/code&gt;, то есть без обрезания фона совсем.&lt;/p&gt;
  &lt;p id=&quot;D0AN&quot;&gt;В этой части нам еще раз показывают принцип работы &lt;strong&gt;множественных фонов&lt;/strong&gt; — в каждом специфичном фоновом свойстве порядок значений через запятую сопоставляется с порядком указанным в &lt;code&gt;background-image&lt;/code&gt;. &lt;/p&gt;
  &lt;p id=&quot;8UIv&quot;&gt;Мы уже рассматривали эту особенность когда строили &lt;a href=&quot;https://blog.arkhelvetios.ru/box-shadow-linear-gradient#1q5k&quot; target=&quot;_blank&quot;&gt;множественные градиенты&lt;/a&gt; и проставляли им &lt;code&gt;background-position&lt;/code&gt;. Кстати, о нём. У свойства &lt;strong&gt;позиции фонового изображения&lt;/strong&gt; есть возможность указать не просто числовые координаты от левого верхнего угла, а уточнить сторону от которой надо вести отсчет, например:&lt;/p&gt;
  &lt;pre id=&quot;8lE8&quot; data-lang=&quot;css&quot;&gt;background-position: right 30px bottom 60px; /* справа 30px, снизу 60px */
background-position: left 50px bottom 10px; /* слева 50px, снизу 10px */&lt;/pre&gt;
  &lt;p id=&quot;L5O8&quot;&gt;И последним свойством рассмотрим знакомый нам &lt;code&gt;background-repeat&lt;/code&gt;, отвечающий за &lt;strong&gt;повторение фонового изображения&lt;/strong&gt;. Во-первых, он может принимать сразу два значение — первое отвечает за повтор по горизонтали, а второй по вертикали. Во-вторых, имеет в своем запасе два очень крутых значения, которые будто из флексбоксов и гридов (или наоборот?):&lt;/p&gt;
  &lt;ul id=&quot;RIQ8&quot;&gt;
    &lt;li id=&quot;xD7X&quot;&gt;Значение &lt;code&gt;round&lt;/code&gt; — изображение будет повторятся, но не будет обрезаться у краёв элемента. Картинка будет растягиваться, чтобы заполнить некратные размеру изображения зазоры. Это поведение ну прям &lt;a href=&quot;https://blog.arkhelvetios.ru/easy-grids#lQfB&quot; target=&quot;_blank&quot;&gt;о-очень похоже&lt;/a&gt; на работу функций &lt;code&gt;repeat()&lt;/code&gt; и &lt;code&gt;minmax()&lt;/code&gt; с &lt;code&gt;auto-fit&lt;/code&gt; в гридах.&lt;/li&gt;
    &lt;li id=&quot;yahf&quot;&gt;Значение &lt;code&gt;space&lt;/code&gt; — изображение тоже не обрезается, но и не растягивается. Зазоры компенсируются расстоянием между изображениями, которые равномерно распределяются по пространству блока. Их поведение тоже очень похоже на уже знакомый нам &lt;code&gt;space-between&lt;/code&gt; в &lt;a href=&quot;https://blog.arkhelvetios.ru/flexy-flexbox#W9S0&quot; target=&quot;_blank&quot;&gt;выравнивании&lt;/a&gt; флекс-итемов во флекс-контейнере. &lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;I1ri&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;7sGa&quot;&gt;Рамки&lt;/h3&gt;
  &lt;p id=&quot;71Y7&quot;&gt;Для начала отметим, что помимо &lt;code&gt;border&lt;/code&gt; существует еще и &lt;strong&gt;внешняя рамка&lt;/strong&gt; или «обводка» &lt;code&gt;outline&lt;/code&gt;. У нее аналогичная запись, но ей нельзя задать какую-либо сторону отдельно, то бишь только всему элементу. &lt;/p&gt;
  &lt;p id=&quot;d9Bj&quot;&gt;Еще одна особенность обводки &lt;code&gt;outline&lt;/code&gt; — она не учувствует в расчёте размера бокса и строится после &lt;code&gt;border&lt;/code&gt; и, соответственно, может залезать на соседние элементы.&lt;/p&gt;
  &lt;p id=&quot;Ugg0&quot;&gt;У обводки есть уникальное свойство &lt;code&gt;outline-offset&lt;/code&gt;, которое отвечает за отступ от элемента или рамки. Причем, принимает как положительные значения — отступ во вне, так и отрицательные — обводка сожмётся внутрь.&lt;/p&gt;
  &lt;p id=&quot;W1d6&quot;&gt;Пару слов про &lt;strong&gt;скругление углов&lt;/strong&gt; &lt;code&gt;border-radius&lt;/code&gt; — мы &lt;a href=&quot;https://blog.arkhelvetios.ru/advance-workshop-academy#54zz&quot; target=&quot;_blank&quot;&gt;уже знаем&lt;/a&gt;, что можно задавать скругление каждому углу отдельно. Оказывается, для этого даже есть специальные отдельные свойства — &lt;code&gt;border-top-left-radius&lt;/code&gt;, &lt;code&gt;border-top-right-radius&lt;/code&gt;, короче, &lt;code&gt;border-угол-radius&lt;/code&gt;.&lt;/p&gt;
  &lt;p id=&quot;Bn1V&quot;&gt;Мало того, оказывается, скругление можно задать эллиптическое, то есть задать ширину и высоту круга по которому будет скругляться угол:&lt;/p&gt;
  &lt;pre id=&quot;Hi7T&quot; data-lang=&quot;css&quot;&gt;/* горизонтальный радиус 30px, вертикальный 15px */
border-top-right-radius: 30px 15px;&lt;/pre&gt;
  &lt;figure id=&quot;636x&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://htmlacademy.ru/assets/courses/88/img/border-radius-theory-2.jpg&quot; width=&quot;289&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;yY3r&quot;&gt;Всё это безобразие можно записать и в короткой форме &lt;code&gt;border-radius&lt;/code&gt; — радиусы задаются через &lt;code&gt;/&lt;/code&gt;, при этом можно также задать сразу для всех углов:&lt;/p&gt;
  &lt;pre id=&quot;TlLf&quot; data-lang=&quot;css&quot;&gt;/* горизонтальный радиус всех углов 10px, вертикальный 5px */
border-radius: 10px / 5px;

/* разные горизонтальные и вертикальные радиусы у каждого угла */
border-radius: 10px 20px 30px 40px / 5px 15px 25px 35px;&lt;/pre&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;5xrV&quot;&gt;Далее мы переходим к обширной теме — &lt;strong&gt;фоновое изображение рамки&lt;/strong&gt; и семейство свойств отвечающих за это — &lt;code&gt;border-image&lt;/code&gt;.&lt;/p&gt;
  &lt;p id=&quot;VafN&quot;&gt;За &lt;strong&gt;источник изображения&lt;/strong&gt; отвечает свойство &lt;code&gt;border-image-source&lt;/code&gt; и его синтаксис аналогичен свойству &lt;code&gt;background-image&lt;/code&gt;, но для рамок.&lt;/p&gt;
  &lt;pre id=&quot;h8vw&quot; data-lang=&quot;css&quot;&gt;border-image-source: url(&amp;quot;image.jpg&amp;quot;);&lt;/pre&gt;
  &lt;p id=&quot;rfaf&quot;&gt;Однако, свойство для рамок работает немного иначе — по умолчанию изображение не растягивается как подложка под рамкой, как ожидается, а будет раскидано по углам рамки.&lt;/p&gt;
  &lt;figure id=&quot;uI2n&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/eb/04/eb047507-3d6f-4972-8dab-8e0159e04d96.png&quot; width=&quot;643&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;8OYH&quot;&gt;Дело всё в том, что рамка по свой сути имеет аж 9 областей — 4 угла, 4 стороны и центр. По умолчанию, браузер не умеет подстраивать изображение под задачи рамки, поэтому просто пихает его по углам.&lt;/p&gt;
  &lt;p id=&quot;dOoG&quot;&gt;За &lt;strong&gt;нарезку фонового изображения&lt;/strong&gt; на области для рамки отвечает свойство &lt;code&gt;border-image-slice&lt;/code&gt; — оно принимает от одного до четырёх числовых значений и работает по сути как функция &lt;code&gt;rect()&lt;/code&gt; которую мы уже &lt;a href=&quot;https://blog.arkhelvetios.ru/advance-workshop-academy#LFZo&quot; target=&quot;_blank&quot;&gt;разбирали в Мастерских&lt;/a&gt;.&lt;/p&gt;
  &lt;figure id=&quot;iLQR&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://htmlacademy.ru/assets/courses/88/img/border-slice.jpg&quot; width=&quot;433&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;7bLf&quot;&gt;Кстати, свойство принимает какие-то условные единицы, то есть в самом свойстве, почему-то не надо ставить &lt;code&gt;px&lt;/code&gt; — выдаст ошибку. Одно значение задаёт отступы от своих краёв для всех линий, а отдельно заданные идут в стандартном порядке — верх, право, низ, лево:&lt;/p&gt;
  &lt;pre id=&quot;OBTr&quot; data-lang=&quot;css&quot;&gt;border-image-slice: 60; /* нарезка как на картинке выше */
border-image-slice: 10 20 30 40; /* каждая линия отдельно */&lt;/pre&gt;
  &lt;p id=&quot;BPuc&quot;&gt;Таким образом, мы нарезаем изображение на те самые 9 частей и уже с ними работает браузер. По умолчанию, центральная область скрывается, но это можно изменить подставив в конце значений нарезки ключевое слово &lt;code&gt;fill&lt;/code&gt; — тогда центральная часть перекроет фон, но не перекроет контент блока.&lt;/p&gt;
  &lt;figure id=&quot;JSgf&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/97/02/97027e93-a573-455f-afed-3b8f0276fcf0.png&quot; width=&quot;1061&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;Nb9n&quot;&gt;Изображение на сторонах, по умолчанию, растягиваются под всю длинны рамки, что далеко не для всех ситуаций подойдет. Но этим поведением можно управлять с помощью свойства &lt;code&gt;border-image-repeat&lt;/code&gt; — он отвечает за &lt;strong&gt;способ заполнения фона&lt;/strong&gt; по сторонам рамки. Именно по сторонам!&lt;/p&gt;
  &lt;p id=&quot;KLJR&quot;&gt;Свойство работает похожим на &lt;code&gt;background-repeat&lt;/code&gt; образом, но по умолчанию имеет свой свойство &lt;code&gt;stretch&lt;/code&gt; — которое, как раз, растягивает изображение по сторонам. Остальные значения, такие же:&lt;/p&gt;
  &lt;ul id=&quot;fkzJ&quot;&gt;
    &lt;li id=&quot;PTcX&quot;&gt;&lt;code&gt;repeat&lt;/code&gt; — повторяет части в размере отрезка, заполняя сторону полностью, при этом обрезает изображение в конце, если оно не поместилось.&lt;/li&gt;
    &lt;li id=&quot;CzxA&quot;&gt;&lt;code&gt;round&lt;/code&gt; — работает абсолютно также как и у фона блока, крайне полезный и универсальный вариант.&lt;/li&gt;
    &lt;li id=&quot;tnoj&quot;&gt;&lt;code&gt;space&lt;/code&gt; — тоже самое, работает аналогично значению из фона блока, но в тренажёре пишут мол, не везде поддерживается и часто заменяется на значение &lt;code&gt;repeat&lt;/code&gt;.&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;pVyJ&quot;&gt;Следующее свойство &lt;code&gt;border-image-width&lt;/code&gt; — оно отвечает за &lt;strong&gt;размер уже нарезанных областей&lt;/strong&gt;. Синтаксис похож на &lt;code&gt;margin&lt;/code&gt; — одно значение для всех сторон, два для горизонтальных и вертикальных, четыре для всех сторон отдельно.&lt;/p&gt;
  &lt;p id=&quot;CwHt&quot;&gt;По умолчанию, размер области равен размеру рамки, причем неважно на какие куски мы нарезали изображение — это отдельная, как бы, сущность, можно сказать отдельные изображения для каждого сектора. &lt;/p&gt;
  &lt;p id=&quot;kPH3&quot;&gt;Расчёт идет от внешней границы рамки. Если размер фонового изображения области рамки задать больше чем размер рамки, то изображение начнёт залезать на фон блока, даже если не задан &lt;code&gt;fill&lt;/code&gt;.&lt;/p&gt;
  &lt;p id=&quot;SmoM&quot;&gt;И последним рассмотрим свойство &lt;code&gt;border-image-outset&lt;/code&gt; — оно отвечает за &lt;strong&gt;смещение фонового изображения рамки&lt;/strong&gt; от элемента. Работает примерно как &lt;code&gt;outline-offset&lt;/code&gt;, но принимает только положительные значения.&lt;/p&gt;
  &lt;p id=&quot;ERJL&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;uArk&quot;&gt;Фигуры из рамок&lt;/h3&gt;
  &lt;p id=&quot;tEWl&quot;&gt;У рамок есть одно интересное свойство — каждая сторона строится по сути в виде трапеции, а при нулевом размере блока превращается в треугольник.&lt;/p&gt;
  &lt;figure id=&quot;p9eT&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/41/fb/41fbe45c-f5a1-49c0-84c3-73043a5fe87f.png&quot; width=&quot;700&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;4dv9&quot;&gt;Таким образом, у нас в арсенале фигур еще две — квадраты и прямоугольники строить легче всего, круги и эллипсы можно строить через &lt;code&gt;border-radius&lt;/code&gt;, а теперь и треугольники с трапециями. &lt;/p&gt;
  &lt;p id=&quot;mY80&quot;&gt;Вторая часть про рамки посвящена такой мини-мастерской — мы строим стрелки и некоторые элементы интерфейса. Насколько это применяется в реальной жизни вопрос открытый, но прикольно. Конспектировать там, правда, нечего.&lt;/p&gt;
  &lt;p id=&quot;RWVP&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;lk0n&quot;&gt;Испытания&lt;/h3&gt;
  &lt;p id=&quot;ehHe&quot;&gt;Два испытания и оба на рамки, с фонами мы, видимо, наигрались в Catademy или как её там. Первое испытание на круглую рамку:&lt;/p&gt;
  &lt;figure id=&quot;0b7a&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://sun9-85.userapi.com/impg/b-blMge1CUhSQcNFLCtvugIbLIaD_6Qi60tnIA/jcD9Fy6Sa80.jpg?size=1320x924&amp;quality=96&amp;sign=63da0d7f6c0c90f8f9e4d9970af3a3ee&amp;type=album&quot; width=&quot;1320&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;F6i6&quot;&gt;Тут почти все рассмотренные свойства части задействованы, включая фоновые. Второе испытание посвящено особенностям рамок и построению из них всяких фигур. Всё свёрстано, только подобрать селекторы.&lt;/p&gt;
  &lt;figure id=&quot;cGyp&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://sun9-6.userapi.com/impg/KNCb6jnDUNrZsCNsKJzrfzERC9nh8tsvgQVO2Q/FptDpre38oI.jpg?size=1321x923&amp;quality=96&amp;sign=b829a08aad01510669a404477ba07c07&amp;type=album&quot; width=&quot;1321&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;rK9c&quot;&gt;&lt;/p&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;I1E1&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;RjW7&quot;&gt;Тонкости получаются какие-то не тонкие, я надеялся будет одна коротенькая статья. Ну да ладно! В следующий раз быстренько разберёмся с тонкостями в оформлении текста и посмотрим на CSS-таблицы.&lt;/p&gt;
  &lt;p id=&quot;zTpj&quot;&gt;Спасибо большое за внимание! Я стараюсь ускорять темп, так как тренажёры затянулись уже что-то.&lt;/p&gt;
  &lt;p id=&quot;LqYO&quot;&gt;По поводу ссылок на предыдущие статьи — я решил пока перестать городить их тут, это тот еще геморрой и занимают они место, не очень красиво. Я скорее всего как-нибудь сделаю такой «пост-sitemap» и буду просто ссылаться на него, а пока пусть будет просто чистенько. &lt;/p&gt;
  &lt;p id=&quot;TlDT&quot;&gt;А вот соц.сеточки я оставлю! Я, кстати, завёл еще страницу на Facebook и заодно буду оставлять свой Instagram. Максимальное присутствие!&lt;/p&gt;
  &lt;section style=&quot;background-color:hsl(hsl(263, 48%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;RC2J&quot; data-align=&quot;center&quot;&gt;&lt;a href=&quot;https://t.me/arkhelvetios&quot; target=&quot;_blank&quot;&gt;Telegram&lt;/a&gt; — &lt;a href=&quot;https://twitter.com/arkhelvetios&quot; target=&quot;_blank&quot;&gt;Twitter&lt;/a&gt; — &lt;a href=&quot;https://www.instagram.com/arkhelvetios/&quot; target=&quot;_blank&quot;&gt;Instagram&lt;/a&gt; — &lt;a href=&quot;https://www.facebook.com/arkhelvetios&quot; target=&quot;_blank&quot;&gt;Facebook&lt;/a&gt; — &lt;a href=&quot;https://vk.com/arkhelvetios&quot; target=&quot;_blank&quot;&gt;VK&lt;/a&gt;&lt;/p&gt;
  &lt;/section&gt;
  &lt;p id=&quot;ZtgO&quot;&gt;Заходите куда удобно вам и подписывайтесь! Еще раз спасибо за внимание!&lt;/p&gt;
  &lt;tt-tags id=&quot;axN4&quot;&gt;
    &lt;tt-tag name=&quot;html&quot;&gt;#html&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;css&quot;&gt;#css&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;html5&quot;&gt;#html5&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;css3&quot;&gt;#css3&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;frontend&quot;&gt;#frontend&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;front_end&quot;&gt;#front_end&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;обучение&quot;&gt;#обучение&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;it&quot;&gt;#it&lt;/tt-tag&gt;
  &lt;/tt-tags&gt;

</content></entry><entry><id>helvetios:keksby</id><link rel="alternate" type="text/html" href="https://teletype.in/@helvetios/keksby?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=helvetios"></link><title>Испытание «Великий Кексби» — Тренажёр HTML Academy</title><published>2022-06-19T22:22:58.821Z</published><updated>2022-06-19T22:54:24.203Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img3.teletype.in/files/a0/3c/a03c2716-bb88-45ec-94d7-b09e067cd14f.png"></media:thumbnail><category term="webdev" label="Веб-разработка"></category><tt:hashtag>html</tt:hashtag><tt:hashtag>css</tt:hashtag><tt:hashtag>html5</tt:hashtag><tt:hashtag>css3</tt:hashtag><tt:hashtag>frontend</tt:hashtag><tt:hashtag>front_end</tt:hashtag><tt:hashtag>обучение</tt:hashtag><tt:hashtag>it</tt:hashtag><summary type="html">&lt;img src=&quot;https://img4.teletype.in/files/bb/67/bb67d0da-2cba-4122-8ad1-31ccbd2a34e0.png&quot;&gt;Мы изучили достаточно для того, чтобы приступить к самому большому испытанию в тренажёрах Академии. «Великий Кексби» — это целых 13 частей практики, разделённых на два блока. Или не совсем. В этой статье разберём всё испытание.</summary><content type="html">
  &lt;figure id=&quot;VaEl&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/bb/67/bb67d0da-2cba-4122-8ad1-31ccbd2a34e0.png&quot; width=&quot;1200&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;74nW&quot;&gt;Мы изучили достаточно для того, чтобы приступить к самому большому испытанию в тренажёрах Академии. «Великий Кексби» — это целых 13 частей практики, разделённых на два блока. Или не совсем. В этой статье разберём всё испытание.&lt;/p&gt;
  &lt;p id=&quot;UZMo&quot;&gt;&lt;/p&gt;
  &lt;nav&gt;
    &lt;ul&gt;
      &lt;li class=&quot;m_level_1&quot;&gt;&lt;a href=&quot;#sygG&quot;&gt;Введение&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_1&quot;&gt;&lt;a href=&quot;#GT59&quot;&gt;Этап 1 — Вёрстка&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_1&quot;&gt;&lt;a href=&quot;#Famz&quot;&gt;Этап 2 — Стилизация&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_2&quot;&gt;&lt;a href=&quot;#XICh&quot;&gt;Сетка &lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_2&quot;&gt;&lt;a href=&quot;#U5qY&quot;&gt;Макет&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_2&quot;&gt;&lt;a href=&quot;#QbZE&quot;&gt;Проверка задания&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_1&quot;&gt;&lt;a href=&quot;#v6Fv&quot;&gt;Итог&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/nav&gt;
  &lt;p id=&quot;t0K6&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;sygG&quot;&gt;Введение&lt;/h2&gt;
  &lt;p id=&quot;EH4F&quot;&gt;Немного поясню почему «не совсем». Не смотря на то, что частей 13, а заданий итого аж 166, но по сути Испытаниями являются только две части в конце каждого блока. &lt;/p&gt;
  &lt;p id=&quot;b26z&quot;&gt;Остальные части это обычные уроки с подводкой к самостоятельной работе. Разница в том, что тут мы почти всё пишем ручками с нуля и общая идея – вёрстки проекта, а не отдельно взятой задачи.&lt;/p&gt;
  &lt;p id=&quot;zl1h&quot;&gt;Испытание заключается в самостоятельной вёрстке макета — нам дают сам макет в виде картинки, архив с текстом и изображениями. Верстать надо у себя в редакторе, а не в браузере. Макет отличается от того, что был в уроках, но сильно похож структурно.&lt;/p&gt;
  &lt;p id=&quot;8gTS&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;GT59&quot;&gt;Этап 1 — Вёрстка&lt;/h2&gt;
  &lt;p id=&quot;VMku&quot;&gt;Первый этап на 90% состоит из разметки в HTML. Только последние несколько уроков касаются CSS в таблицах, но это не существенно.&lt;/p&gt;
  &lt;figure id=&quot;T8rn&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/21/49/214901ec-3276-4580-9dba-50717c8f4fdf.png&quot; width=&quot;449&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;vP36&quot;&gt;И тут сразу хочу поругать эту часть тренажёра за неактуальность или, может быть, ленивость. Помнится, что нам чуть ли не сразу &lt;a href=&quot;https://blog.arkhelvetios.ru/intro-html-css-part2#Hyz2&quot; target=&quot;_blank&quot;&gt;рассказали&lt;/a&gt; про «диватоз» и семантическую вёрстку. И вот мы дошли до большого испытания где мы… верстаем все на &amp;lt;div&amp;gt;&amp;#x27;ах. Прям вообще всё, включая шапку и подвал.&lt;/p&gt;
  &lt;p id=&quot;bivt&quot;&gt;Наверное, это такое «упрощение», но мы же уже прошли всё это, мы уже знаем как семантически корректно верстать. Почему тут всё нарочно наоборот? Обескураживает. Окей, я понимаю, этот Кексби может быть сделан еще когда гридов даже не было, но, на мой взгляд, такое себе оправдание.&lt;/p&gt;
  &lt;p id=&quot;3ETd&quot;&gt;Первый пять частей мы верстаем по указке, а вот шестая часть «Промежуточное испытание» уже самостоятельная работа. Нам дают архив с материалами, картинку и вперёд!&lt;/p&gt;
  &lt;p id=&quot;ucIl&quot;&gt;Свёрстанный результат нужно обратно заархивировать и отправить на проверку. Надо сказать, что тут сделано все очень круто, я впечатлён. &lt;/p&gt;
  &lt;figure id=&quot;sgzY&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/bb/8b/bb8b7424-2f97-4455-99d5-2900caef4c0f.png&quot; width=&quot;762&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;b7xu&quot;&gt;Однако, из-за того, что задание проверяется автоматически, код нужно подводить к определённому шаблону. Про этот шаблон сказано в сопроводительном видео и сразу за ним есть «эталонный» вариант.&lt;/p&gt;
  &lt;p id=&quot;kHS1&quot;&gt;То есть работа всё-таки не совсем самостоятельная, можно сверяться по ходу написания. Пусть это всего лишь картинки, но по ней можно точно понять, что от тебя требуется в итоге:&lt;/p&gt;
  &lt;figure id=&quot;adF8&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/c9/60/c96094bc-aae1-484c-9135-c785e6d82a7f.png&quot; width=&quot;364&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;MExa&quot;&gt;Кстати, я пользовался Visual Studio Code и, наверное, продолжу работать на нём. Пока всё удобно и интуитивно понятно:&lt;/p&gt;
  &lt;figure id=&quot;CTlo&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/21/4e/214e23fb-c7fb-4eee-8d11-5eac59d1f9c4.png&quot; width=&quot;1920&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;qIbQ&quot;&gt;Итак, готовую работу отправляем на проверку и в течение минуты получаем результат:&lt;/p&gt;
  &lt;figure id=&quot;hC9o&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://sun9-55.userapi.com/s/v1/ig2/TE7bKyNIXTsq7JH8c_gFUSsGjYXyxFFEPzF8yHuWUdDnMx6k2afaO6hUhqRff3oFwSzp_a54IaTonBoala0Spoe3.jpg?size=1315x634&amp;quality=96&amp;type=album&quot; width=&quot;1315&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;joAO&quot;&gt;У меня получилось всё с первого раза, кроме блока с формой, там проглядел один перенос строки &lt;code&gt;&amp;lt;br&amp;gt;&lt;/code&gt;. Повторно отправил уже полностью верно.&lt;/p&gt;
  &lt;p id=&quot;jnFV&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;Famz&quot;&gt;Этап 2 — Стилизация&lt;/h2&gt;
  &lt;p id=&quot;Ktqo&quot;&gt;Технически реализовано почти также как и первый этап — первые части блока вводные, показывают как и какими методами будем стилизовать.&lt;/p&gt;
  &lt;figure id=&quot;qhpu&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/f5/8f/f58f70d8-19da-4c1f-a533-60c1259f173c.png&quot; width=&quot;441&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;FFIO&quot;&gt;Этот блок полностью про CSS, мы кое-где изредка добавляем класс и добавляем контейнер «центровщик» в разметку. Итоговая проверка проходит в таком же формате — нужно отправить архив, теперь уже с прилинкованным файлом стилей.&lt;/p&gt;
  &lt;p id=&quot;gKBv&quot;&gt;Однако, есть несколько нюансов, которые я бы хотел написать. Простите, но часть вызвала много негативных эмоций.&lt;/p&gt;
  &lt;p id=&quot;daoi&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;XICh&quot;&gt;Сетка &lt;/h3&gt;
  &lt;p id=&quot;TOBq&quot;&gt;Методы стилизации выбраны, мягко говоря, интересные. Базовая стилизация — всё ок, а вот сетки мы строим на &lt;code&gt;float&lt;/code&gt;. Да, флоаты, да, с &lt;code&gt;clearfix&lt;/code&gt; и всем вытекающим из этого геморроем в позиционировании, например, трёх колонок. &lt;/p&gt;
  &lt;figure id=&quot;839r&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/45/24/452453c6-bf25-4683-938b-081ad175b85d.png&quot; width=&quot;323&quot; /&gt;
    &lt;figcaption&gt;Да он нам и нахрен не нужОн, этот грид ваш!&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;Qm7u&quot;&gt;Когда я проходил часть про сетки на &lt;code&gt;float&lt;/code&gt; я уже тогда понял, что эта технология как минимум не удобная и как оказалось, устаревшая. Почему она в самом большом испытании на все тренажёры? Ну какие нафиг флоуты в 2022?&lt;/p&gt;
  &lt;figure id=&quot;6rr0&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/ab/6c/ab6c98d2-cbe3-46ee-9bf7-fa937c5a25c5.png&quot; width=&quot;967&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;C4sd&quot;&gt;Да, я понимаю, Кексби как и Кекстаграм, видимо, делались давно, судя по всему, 2014–2016 года или около того. Хотя, даже тогда флексы уже хорошо поддерживались. Оправдывает ли это академию?&lt;/p&gt;
  &lt;p id=&quot;ODRa&quot;&gt;Да, я понимаю, что до сих пор огромное количество сайтов свёрстано на флоатах, тот же VK, например, и есть гуру синдрома утёнка, кто и сейчас верстает на них.&lt;/p&gt;
  &lt;p id=&quot;OS47&quot;&gt;Но зачем новичку, который потенциально ни разу не верстал даже на удобных современных сетках, давать самостоятельную работу на супер устаревшем методе? При том, что мы уже прошли все эти методы!&lt;/p&gt;
  &lt;p id=&quot;sHxr&quot;&gt;Ах, да, кстати, микросетки — все возможные кнопки и иконки мы тоже делаем на &lt;code&gt;inline-block&lt;/code&gt;, тоже с вытекающими, в плане пробелов, нулевого размера шрифта и прочих костылей. Да, это иногда применимо, но тут это везде.&lt;/p&gt;
  &lt;p id=&quot;bcRL&quot;&gt;Ладно, может это делается намеренно, ради «тренировки», я не знаю. Допускаю, что у меня бомбит от своего невежества и на самом деле флоат — это мастхэв (сомневаюсь).&lt;/p&gt;
  &lt;p id=&quot;JRzL&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;U5qY&quot;&gt;Макет&lt;/h3&gt;
  &lt;p id=&quot;D3g8&quot;&gt;Едем дальше. На этом этапе нам дают уже не картинку JPG, а полноценный макет в PSD формате со слоями и элементами, что очень круто. Можно сказать, бесплатный практический макет с возможностью его проверить!&lt;/p&gt;
  &lt;p id=&quot;V6B1&quot;&gt;Но макет полное говно. &lt;/p&gt;
  &lt;p id=&quot;u3wZ&quot;&gt;Начиная от критичных погрешностей в расположении элементов, заканчивая неправильными, не подходящими параметрами текста. Я уже молчу про слои — это просто в кучу сваленные шейпы без подписей, без каких-то группировок.&lt;/p&gt;
  &lt;figure id=&quot;aHq5&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/aa/b7/aab7c495-efac-4a0d-9e12-6a67612df791.png&quot; width=&quot;333&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;35TF&quot;&gt;«Верстальщику не нужны слои», кто-то скажет. А я скажу — попробуйте выделить авто-селектом шейп толщиной 1px чтобы понять «задан ли ему такой тусклый цвет?» или «цвет с прозрачностью?» или «прозрачность задана самой фигуре?».&lt;/p&gt;
  &lt;p id=&quot;qC4g&quot;&gt;Почему это меня беспокоит? Да потому, что все три варианта есть на макете. Часть рамок &lt;code&gt;border&lt;/code&gt; в сплошном цвете, а часть в полупрозрачном. А учитывая, что прозрачность &lt;code&gt;opacity&lt;/code&gt; можно задать еще и слою отдельно — работа с таким макетом превращается в то еще удовольствие. Сиди выясняй — это #404040 или это чёрный полупрозрачный?&lt;/p&gt;
  &lt;figure id=&quot;p5Z7&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/a3/a4/a3a423cc-6dbb-445e-b0fc-dd32ffa4277d.png&quot; width=&quot;666&quot; /&gt;
    &lt;figcaption&gt;Здесь обводка черная, а у слоя прозрачность 30%. &lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;figure id=&quot;WndP&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/c8/e6/c8e6b50e-a95a-4d2d-9e08-173d910d179f.png&quot; width=&quot;623&quot; /&gt;
    &lt;figcaption&gt;А здесь это цвет такой прост))00))0&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;uwfF&quot;&gt;Но это всё фигня — дизайнеры разные бывают, тут ок, хотя я бы попросил всё-таки как-то привести в порядок это всё. Ладно.&lt;/p&gt;
  &lt;p id=&quot;lInl&quot;&gt;А вот числовые ошибки уже как-то нихрена не «ладно». У всех заголовков, включая подзаголовки и разные акцентные надписи — в макете указано неверное значение высоты строки &lt;code&gt;line-height&lt;/code&gt;.&lt;/p&gt;
  &lt;figure id=&quot;cR9z&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/0c/07/0c07be8b-ed87-4d1e-b579-39e5dc494e3f.png&quot; width=&quot;549&quot; /&gt;
    &lt;figcaption&gt;Высота строки у заголовка секции в макете указана 61px&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;eqJx&quot;&gt;Везде указано либо 61px, либо там 41px/31px — уже лень искать. Но везде вот этот странный 1 пиксель сверху. Я сначала не придал значения, но при проверке у меня везде, во всех блоках, как бы я там не танцевал туда-сюда по 5px — в эталон проверки не попадало.&lt;/p&gt;
  &lt;p id=&quot;vgh8&quot;&gt;Поменял все на 60px и надо же! Сработало! Почему я уверен, что это ошибка макета, а не я где-то упустил эти пиксели? После прохождения всех блоков — получаешь эталонный 100%-й вариант. И что бы вы думали?&lt;/p&gt;
  &lt;figure id=&quot;aAdM&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/d2/de/d2de3d41-7f02-4699-a77a-9a512916bb92.png&quot; width=&quot;218&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;b6nP&quot;&gt;И там такого дофига. Размеры таблиц практически наугад задаёшь, высоту полей формы в итоге легче задать фиксировано через &lt;code&gt;height&lt;/code&gt;, положение бутылок во втором блоке тоже наугад. &lt;/p&gt;
  &lt;figure id=&quot;pPiC&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/ff/95/ff95b9f6-5acd-474f-885b-5bac85bbfade.png&quot; width=&quot;423&quot; /&gt;
    &lt;figcaption&gt;Это один текстовый блок на две ячейки таблицы. Поди отсюда ноги и растут.&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;8pSz&quot;&gt;Ах да, еще — высота первого блока в макете тоже неправильная, а это влияет на фоновое изображение. Высота в макете 550px, тогда как высота блока которая должна быть оказывается 490px. Потому что.&lt;/p&gt;
  &lt;p id=&quot;K3N0&quot;&gt;«Зачем так придираться?» — спросите вы. Никто же не будет требовать «pixel perfect» от учебного проекта? Тем более такого костыльного?&lt;/p&gt;
  &lt;p id=&quot;C8jU&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;QbZE&quot;&gt;Проверка задания&lt;/h3&gt;
  &lt;p id=&quot;k25U&quot;&gt;Хрен там — скажу я вам! Проверка идёт так же по блокам страницы, но теперь проверяется еще сетка и оформление. Работает также — сравнивается по скрину наложением. Более того проверяется еще и вложенность.&lt;/p&gt;
  &lt;figure id=&quot;ZClC&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/42/b3/42b3867d-8c22-46bf-b38f-aaa9eed74c62.png&quot; width=&quot;576&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;tI2M&quot;&gt;То есть нужно попасть пикселями в эталон без погрешностей, попасть цветом и всеми стилевыми атрибутами и если по вложениям ты что-то поменял, то это тоже ошибка. Например, не забудьте, что лого должно быть в дополнительном контейнере и им обоим надо задать одинаковые размеры.&lt;/p&gt;
  &lt;p id=&quot;5NjT&quot;&gt;В самой проверке тоже есть какие-то придурошные приколы — блок с формой заказа, в сетке явно указывает на дополнительный отступ сверху от текста с призывом, а во вкладке стилей все идеально подходит.&lt;/p&gt;
  &lt;figure id=&quot;4B9u&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/d7/e3/d7e3bae3-c2ff-4eaa-bb50-63570aa1c814.png&quot; width=&quot;971&quot; /&gt;
    &lt;figcaption&gt;Если что – браузерные стили обнулены, дело не в них.&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;lvYu&quot;&gt;И такого там тоже дофига. Большую часть времени ты не занимаешься вёрсткой, ты занимаешься танцами с бубном на одном пальце левой ноги, чтобы понять какой куда там пиксель не попал и почему.&lt;/p&gt;
  &lt;p id=&quot;wEnb&quot;&gt;В итоге я плюнул на это дело — тот случай когда перфекционизм нужно отключать и не трахать себе мозги. Выполнил, в среднем, все блоки и все вкладки на 96-97% и хрен с ними, себе дороже.&lt;/p&gt;
  &lt;figure id=&quot;IQjv&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/58/19/5819de8d-d88d-481d-b7a9-eeb01474763f.png&quot; width=&quot;988&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;rM7a&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;v6Fv&quot;&gt;Итог&lt;/h2&gt;
  &lt;p id=&quot;G3x9&quot;&gt;Самое обидное, что идея просто потрясающая! И сама реализация тоже крутая, но дьявол, сука, в мелочах. Ну почему всё в дивах? Зачем мы учили семантическую вёрстку до этого?&lt;/p&gt;
  &lt;p id=&quot;dNpU&quot;&gt;Ну что мешало сделать задачу на флексах, пусть без всяких &lt;code&gt;flex-grow&lt;/code&gt; и других модификаторов? Да если даже с ними, у нас фиксированный макет, с фиксированной шириной!&lt;/p&gt;
  &lt;p id=&quot;qRnf&quot;&gt;Ну почему такой убогий макет? Почему в нём ошибки? Они намерено там есть? Типа как в некоторых школах специально дают не полную задачу, что бы тренировать ученика задавать уточняющие вопросы? Так это не про тренажёры! У кого тут спрашивать-то?&lt;/p&gt;
  &lt;p id=&quot;sJme&quot;&gt;После прохождения Кексби, да еще и в комбо со спорным Кекстаграмом до этого, у меня появились сомнения стоит ли вообще в Академии продолжать учиться. Может и на курсах всё также? В любом случае, профессия «Фронтендера» меня там уже ждёт, поэтому никуда я уже не денусь.&lt;/p&gt;
  &lt;p id=&quot;K4kq&quot;&gt;&lt;/p&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;E5vl&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;hgD9&quot;&gt;Вот такой вот поток эмоций вызвал у меня этот Кексби. Возможно, на момент выхода он был самый крутой, но сейчас мне прям вот вообще не понравилось.&lt;/p&gt;
  &lt;p id=&quot;iviB&quot;&gt;Вам спасибо большое за внимание и прошу прощения за негатив! Надеюсь, вам хотя бы было весело почитать про мои страдания.&lt;/p&gt;
  &lt;p id=&quot;jX0N&quot;&gt;Ссылки на другие статьи по HTML Academy:&lt;/p&gt;
  &lt;p id=&quot;r7tW&quot;&gt;&lt;a href=&quot;/intro-to-web-development&quot;&gt;Знакомство с Веб-разработкой&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;/intro-html-css-part1&quot;&gt;Знакомство с HTML и CSS&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;/intro-javascript&quot;&gt;Знакомство с JavaScript&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;/intro-php&quot;&gt;Знакомство с PHP&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;/advanced-html-css-part1&quot;&gt;Таблицы и подробно о формах&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;/advanced-html-css-part2&quot;&gt;Наследование, каскады и селекторы&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;/block-model-flow-and-float&quot;&gt;Блочная модель, поток и сетка на float&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;/flexy-flexbox&quot;&gt;Гибкие флексбоксы display: flex&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;/easy-grids&quot;&gt;Удобные сетки на гридах display: grid&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;/why-skip-one-block&quot;&gt;Пропуск блока «Погружение»&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;/position-and-transform&quot;&gt;Позиционирование и двумерные трансформации&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;/box-shadow-linear-gradient&quot;&gt;Теневое искусство и линейные градиенты&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;/css-filters-kekstagram&quot;&gt;CSS-фильтры и Кекстаграм&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;/workshop-academy&quot;&gt;Мастерские&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://blog.arkhelvetios.ru/advance-workshop-academy&quot; target=&quot;_blank&quot;&gt;Продвинутые Мастерские&lt;/a&gt;&lt;br /&gt;…&lt;/p&gt;
  &lt;section&gt;
    &lt;p id=&quot;nhBq&quot;&gt;Остальные статьи можно посмотреть у меня на &lt;a href=&quot;/&quot;&gt;главной странице&lt;/a&gt; блога.&lt;/p&gt;
  &lt;/section&gt;
  &lt;p id=&quot;scdz&quot;&gt;Также мои соц. сетки, которые я продолжаю вести:&lt;/p&gt;
  &lt;p id=&quot;AxOF&quot;&gt;&lt;a href=&quot;https://twitter.com/arkhelvetios&quot; target=&quot;_blank&quot;&gt;Мой Twitter&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://t.me/arkhelvetios&quot; target=&quot;_blank&quot;&gt;Мой Telegram&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://vk.com/arkhelvetios&quot; target=&quot;_blank&quot;&gt;Мой Паблик ВК&lt;/a&gt;&lt;/p&gt;
  &lt;p id=&quot;Z3UO&quot;&gt;Заходите куда удобно вам и подписывайтесь! Еще раз спасибо за внимание!&lt;/p&gt;
  &lt;tt-tags id=&quot;tYzB&quot;&gt;
    &lt;tt-tag name=&quot;html&quot;&gt;#html&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;css&quot;&gt;#css&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;html5&quot;&gt;#html5&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;css3&quot;&gt;#css3&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;frontend&quot;&gt;#frontend&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;front_end&quot;&gt;#front_end&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;обучение&quot;&gt;#обучение&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;it&quot;&gt;#it&lt;/tt-tag&gt;
  &lt;/tt-tags&gt;

</content></entry></feed>