.container больше не нужен
Все верстальщики в своих проектах используют div.container для центрирования контента и этот способ имеет некоторые особенности, от которых можно избавиться. Прочитав эту статью, Вы узнаете про способ, который позволит полностью отказаться от контейнера. Я попытаюсь рассказать о плюсах и минусах использования контейнера и альтернативного способа центрирования контента средствами только лишь css.
P.S. Надеюсь качество GIF’ок позволяет что-то разглядеть.
Изображение выше и код наглядно показывают как работает стандартный контейнер в типовой вёрстке сайта. Наверное все знают, что обычно создается тег section, в него помещается div.container и уже в него помещают различный контент. Он занимает всю ширину экрана, например, до 1170px и когда экран становится больше, то играет роль обёртки и фиксирует контент в центре страницы, не давая ему «разбежаться» в стороны.
Так почему бы сразу не задать эти стили для контента? Если задать эти стили для секции без контейнера, то вроде бы всё смотрится нормально.
Но как только требуется задать фон для секции, ситуация сразу выходит из под контроля:
Если задать для секции фон, внутрь секции положить контейнер с его стилями, а в него уже контент, то всё заработает так, как надо:
Самый очевидный минус контейнера — создание лишних блоков в разметке, которое ведет к увеличению цепочки вложенностей элементов и понижению читаемости кода.
Также создание контейнера может вызвать сложности в названиях классов (иногда нужно придумать дополнительный класс для обёртки внутри контейнера). Это всё просто увеличивает код.
Выше мы рассмотрели самый простой пример. Но если на сайте 15 секций или больше? Это 15 лишних блоков. А если нам внутри контейнера нужно разделить секцию еще на две части и сделать их flex-элементами? Нужно создать div-обёртку, это еще по одному блоку в контейнер. И уже +2 лишних блока на секцию! Как я уже сказал выше — эти div’ные вложенности «мусорят» в разметке. Но возможности css позволяют нам обойтись и без них.
Взяв за основу сетку bootstrap можно значительно упростить себе работу с css медиа-запросами, используя следующий код:
Что он делает? Если кратко, то держит контент всегда в центре и меняет его размеры на разных экранах:
Допустим нам нужна ширина контента 1180px, значит 1920 — 1180 = 740 / 2 = 370px — будут боковые отступы в нашей секции. Смотрим:
Да уж. При уменьшении экрана, наши отступы сжимают контент. Не годится. Может возможно сделать отступы динамическими? Возможно! И ресурсами одного лишь css!
Для этого воспользуемся функцией calc(). На данный момент css-функция calc() поддерживается на 96.5%, что всего на 1% меньше, чем flexbox, а это значит, что её можно смело использовать. Для динамических внутренних отступов нужно выполнить одну математическую операцию.
Давайте уже скорее посмотрим на пример:
UPD: Упросил формулу. Спасибо Metotron0.
Таким образом мы задаём боковые внутренние отступы с помощью функции calc(), которая при любом разрешении экрана высчитывает эти отступы так, чтобы контент был 1180px! Вы только попробуйте.
Можно поиграться с корректирующим значением 590px и сделать контент 1140px или 1170px, как угодно!
Посмотрите сравнение этого метода с контейнером прямо сейчас!
Комбинация с медиа-запросами
Было бы очень хорошо встроить это в сетку от bootstrap, чтобы легче было адаптировать сайт.
Итого на разных размерах экранов мы имеем:
Пример из реальной практики, сравнение методов
Всё еще не видите пользы от метода с динамическими отступами? Тогда давайте взглянем на пример из реальной практики. Надевайте очки разработчика — есть следующая секция (кликабельно):
А теперь посмотрите как это выглядит если использовать динамические отступы:
Только посмотрите как уменьшился код, он стал чище, читать его стало легче. Получилась секция, которая содержит блок с текстом и форму — ничего лишнего! И это всего лишь одна секция. Повторюсь: а если на сайте 15 секций?
Итак, начинаем подводить итоги:
Иначе они перезапишут динамические отступы.
Рекомендации
Мне нравится метод с динамическими внутренними отступами. Попробуйте его вместо привычной «контейнерной» вёрстки и вы быстро заметите как повысилась чистота вашего кода. Если есть какие-то сомнения в этом методе, то пишите их в комментарии — обсудим!
Рекомендую использовать не %, а vw. Чтобы ширина считалась не от родителя, а от ширины области промотора браузера. Так просто надёжнее. Поддержка vw — 96% тут.
Создайте свой шаблон этих стилей с медиа-запросами, например:
Заключение
Метод с динамическими отступами выполняет ту же функцию, что и div.container, но полностью лишён всех его недостатков. Возможно этот метод имеет какие-то подводные камни, но я пока их не встретил. Пока всё работает абсолютно так же, как с контейнером.
Не бойтесь чего-то нового. Просто начните применять этот метод и в скором времени вы почувствуете некоторое облегчение. Используйте css на полную катушку!
Стилизация контейнеров для содержимого веб-страниц
Содержимое веб-страниц должно быть размещено в некоем элементе, ширина которого, ограничивающая ширину содержимого, позволяет пользователям удобно работать с материалами сайта. Такие элементы называют «обёртками» (wrapper) или «контейнерами» (container). Стилизовать контейнеры средствами CSS можно по-разному. Некоторые способы работы с контейнерами ставят дизайнера перед необходимостью решать достаточно сложные задачи.
В этом материале я расскажу о контейнерах для содержимого веб-страниц: о том, как они работают, о том, как ими пользоваться, и о тех случаях, когда лучше обойтись без них. Обратите внимание на то, что я буду использовать здесь термины «обёртка» и «контейнер» как равнозначные.
Общие сведения
Но в современных условиях использование в качестве контейнера элемента может оказаться непрактичным. Контейнер позволяет не допустить выхода дочерних элементов за его границы.
Контейнер не даёт дочерним элементам выходить за его границы
Без использования элемента-обёртки дочерние элементы будут размещаться, ориентируясь на края экрана. Это может быть неудобным для пользователей. Особенно — для тех, которые работают на больших экранах.
Страница без элемента-контейнера, включающего в себя её содержимое
Здесь показано, как элементы, растягиваясь, занимают весь экран. Происходит это в том случае, если в макете страницы нет элемента-контейнера. Полагаю, не следует предлагать пользователям работать с подобными страницами. Позвольте мне объяснить эту мысль.
О необходимости использования контейнеров для содержимого веб-страниц
Использование контейнера для содержимого веб-страниц имеет множество сильных сторон, о которых стоит знать дизайнерам и разработчикам. Вот некоторые из этих сильных сторон:
Настройка элемента-контейнера средствами CSS
Теперь, когда мы поговорили об основах применения контейнеров, и о том, какие преимущества даёт их использование, давайте остановимся на том, как настраивать их средствами CSS.
▍Настройка ширины контейнера
Элемент-контейнер с настроенной шириной
Хотя это — вполне рабочий приём, можно полностью избавиться от свойства width и, как в следующем примере, пользоваться лишь свойством max-width :
Теперь, когда мы нашли подходящий механизм настройки ширины контейнера, давайте поговорим о том, как выровнять контейнер по центру страницы.
▍Выравнивание контейнера по центру страницы
Контейнер, выровненный по центру страницы
Для того чтобы выровнять контейнер по центру страницы, нужно, при настройке его внешних отступов, воспользоваться значением auto для левого и правого отступов:
Вот как, в соответствии со спецификацией CSS, ведут себя отступы, которым назначено значение auto :
Если margin-left и margin-right установлены в значение auto, то значения, которые будут использованы для этих отступов, будут одними и теми же. Это позволяет центрировать элемент по горизонтали относительно краёв содержащего его блока.
Если вас интересуют подробности об использовании ключевого слова auto в CSS — взгляните на эту мою статью.
▍Настройка левого и правого внутренних отступов
Горизонтальные (левый и правый) внутренние отступы
При проектировании контейнера важно уделить внимание настройке его левого и правого внутренних отступов. Когда размер области просмотра меньше максимальной ширины контейнера, это приведёт к тому, что края контейнера будут прижаты к границам области просмотра. Вот пример стилизации контейнера, в котором предусмотрены внутренние отступы:
Настроив внутренние отступы контейнера, мы можем быть уверены в том, что края контейнера, в любом случае, будут находиться как минимум в 16px от краёв области просмотра, даже в том случае, если ширина области просмотра окажется меньше максимальной ширины контейнера. Внутренние отступы — это нечто вроде защитного механизма, который не даёт границам контейнера прижиматься к границам области просмотра даже в том случае, когда область просмотра уже, чем максимальная ширина контейнера.
▍Использование процентных значений при настройке контейнеров
Использование процентных значений при настройке контейнеров и ситуации, когда значение max-width: 90% приводит к приемлемым и неприемлемым результатам
Хотя этот подход оказался вполне рабочим, выяснилось, что на больших экранах 90% ширины области просмотра — это слишком много. Но данную проблему можно решить, воспользовавшись медиа-запросом:
В результате оказывается, что, используя процентное значение, мы усложняем CSS-код. Для того чтобы избавить себя от необходимости применения медиа-запроса, мы можем использовать фиксированное значение для ширины. Ещё одно решение, предложенное в этом твите, заключается в применении комбинации свойств width: 90% и max-width: 1170px :
Это — интересный подход, но я предпочёл бы настраивать внутренние отступы самостоятельно, не полагаясь на процентные значения.
▍Свойство display элемента-контейнера
Я не рекомендую этого делать, так как это идёт вразрез с идеей разделения ответственностей. Элемент-контейнер, «обёртка», это сущность, предназначение которой заключается в том, чтобы «оборачивать» другие элементы. Если нужно разместить дочерние элементы контейнера в сетке, тогда стоит добавить в контейнер ещё один
Пусть имеется такой контейнер:
Задавать свойство display: grid подобного элемента не рекомендуется из-за того, что такой элемент может использоваться на разных страницах. Его особые настройки могут случайно привести к нарушению размещения элементов. Вот неудачный вариант настройки контейнера, о котором идёт речь:
Лучше будет использовать такой HTML-код:
Элемент с классом featured-news можно стилизовать так:
Обратите внимание на то, что в этом примере мы использовали отдельный элемент
в качестве ещё одной обёртки для содержимого страницы. На имена классов, использованных здесь, можете внимания не обращать. Для решения подобной задачи можно подобрать более удачные имена классов, которые подойдут для многократного использования на различных страницах сайта. Однако именование CSS-сущностей выходит за рамки данного материала.
▍Настройка внешних отступов, разделяющих элементы-контейнеры
Помните, как выше я не рекомендовал использование сокращённого способа настройки внешних отступов для центрирования элемента-контейнера? Речь шла о такой конструкции:
Хотя это — вполне рабочий стиль, в том случае, если на странице имеется несколько элементов-обёрток, и между ними должно быть некоторое расстояние, применение подобного стиля может привести к путанице. Если вы, по какой-то причине, решите уточнить стилизацию элемента-обёртки, применив дополнительный класс, то настройка внешних отступов с помощью этого класса не даст нужных результатов из-за особенностей расчёта значений специфичности CSS-правил.
Я имею в виду такую схему стилизации:
Теперь поговорим о настройке внешних отступов элементов. При работе над каждым своим проектом я готовлю набор вспомогательных классов для настройки внутренних и внешних отступов. Я использую их там, где они нужны. Взгляните на следующий рисунок.
Автономный контейнер и контейнер внутри элемента
Контейнер внутри полноэкранного элемента
В некоторых случаях бывает так, что есть элемент с фоном, занимающий 100% ширины области просмотра, а внутри этого элемента имеется элемент-контейнер. Эта схема похожа на ту, которую мы рассматривали в предыдущем разделе.
HTML-структура страницы в такой ситуации может выглядеть так:
Элемент занимает 100% ширины области просмотра. Этому элементу можно назначить фоновое изображение или фоновый цвет. Контейнер, находящийся внутри этого элемента, не даёт содержимому занимать всю ширину области просмотра.
Элемент занимает всю ширину области просмотра, контейнер ограничивает пространство, в котором выводится содержимое страницы
На этом рисунке у элемента задано фоновое изображение. Он занимает всю ширину области просмотра, а содержимое страницы, выводимое в контейнере, ограничено шириной контейнера.
Нужно ли заключать в контейнер содержимое верхнего блока страницы?
Нужен ли контейнер для оформления верхнего блока страницы, который часто называют «Hero Section»? Это зависит от каждой конкретной ситуации. Исследуем два самых распространённых подхода к оформлению верхних блоков страниц.
Первый подход предусматривает центровку содержимого блока и ограничение ширины содержимого.
Ширина содержимого верхнего блока страницы ограничена
Второй вариант предусматривает распределение содержимого в пределах верхнего блока.
Содержимое распределено в пределах верхнего блока страницы
Для того чтобы лучше разобраться в этих паттернах, предлагаю исследовать особенности их внутреннего устройства.
Верхний блок страницы, содержимое которого выровнено по центру
Возможно, разрабатывая верхний блок страницы, вам захочется разместить в соответствующем элементе некое содержимое и выровнять его по центру без использования элемента-контейнера.
При стилизации вышеприведённого HTML-кода выровнять его содержимое по центру можно, воспользовавшись свойством text-align :
При таком подходе всё будет выглядеть достойно до тех пор, пока не изменится ширина окна браузера. Вот разбор проблем, которые это может вызвать.
▍Проблема №1: содержимое раздела прижимается к краям области просмотра
Так как в данном примере не настроены правый и левый внутренние отступы, содержимое раздела будет размещено вплотную к границам этого раздела. Это создаёт неудобства для пользователей, так как им сложнее будет читать содержимое верхнего блока страницы.
Содержимое раздела прижато к его краям
▍Проблема №2: слишком большая длина строк текста на экранах большого размера
, может быть очень тяжело читать из-за того, что длина абзаца окажется слишком большой. В соответствии с этим документом, рекомендованное число символов в строке составляет 45-75. Выход длины строки за пределы этого диапазона усложняет чтение.
Длина строки слишком велика
▍Решение проблем
Для решения вышеозначенных проблем можно использовать контейнер. Он позволит и удержать длину строки в разумных пределах, и предотвратить плотное прилегание содержимого к границам раздела.
Как выравнивать контейнер: по центру, или по левому краю страницы?
Я не могу дать однозначного ответа на этот вопрос, однако я видел сайты, контейнеры, используемые на которых, выравниваются на экранах ноутбуков по центру, а на экранах настольных компьютеров — по левому краю страницы.
Примером такого сайта является Techcrunch. Обратите внимание на то, что на экране настольного компьютера содержимое сайта выровнено по левому краю страницы.
Выравнивание содержимого на экране ноутбука и на экране настольного компьютера
Мне нравится работать с сайтами, содержимое которых выровнено по центру. На страницах таких сайтов имеются симметричные отступы слева и справа. Но у того, что содержимое некоторых сайтов выравнивают по левому краю страницы, может быть какая-то причина, о которой я не знаю. Если вы знаете о том, почему это так, дайте мне знать.
Использование CSS-переменных для создания различных вариантов стилизации контейнеров
Редко бывает так, что все элементы-контейнеры, используемые в некоем проекте, имеют одну и ту же ширину. Ширина контейнера может меняться в зависимости от содержимого контейнера и от того, как именно он используется. Большую гибкость в работе с контейнерами даёт использование CSS-переменных. Это, кроме того, весьма современный подход к настройке контейнеров. Рассмотрим пример.
Вот HTML-код контейнера:
Благодаря этому подходу я смог создать особый контейнер, не прибегая при этом к следующим действиям:
Если вам не нравится этот подход из-за использования в нём встроенного стиля для переопределения значения CSS-переменной, вы вполне можете решить эту задачу и с помощью добавления к элементу нового класса. Например — так, как показано ниже.
Так выглядит стиль:
Здесь можно найти рабочий пример.
Использование display: contents
При реализации чего-то, напоминающего этот пример, может понадобиться сделать так, чтобы заголовочный раздел сайта мог бы растягиваться до полной ширины страницы, чтобы его ширина не ограничивалась бы свойствами контейнера.
Заголовочная часть сайта занимает, в ширину, всё доступное пространство
Отзывчивый фон и фиксированное содержимое
В книге CSS Secrets представлена интересная техника, которая может быть использована для стилизации разделов, имеющих отзывчивый фон (фон, способный занимать всю доступную ширину области просмотра) и элемент-контейнер для содержимого. Рассмотрим обычный способ создания макетов подобных разделов.
Здесь значения свойств margin-left: auto и margin-right: auto вычисляются путём взятия половины ширины области просмотра и вычитания из неё ширины содержимого. Того же самого можно добиться с использованием внутренних отступов.
Но дело пока ещё не сделано. На мобильных устройствах содержимое будет прижато к краям области просмотра. Решить эту проблему можно, например, так:
Как вы стилизуете элементы-контейнеры?
Контейнерные запросы в CSS
Как фронтенд-дизайнер я за последние 6 лет не был так взволнован новой CSS-функцией, как сейчас. Благодаря усилиям Мириам Сюзанны и других умных людей прототип контейнерных запросов можно включить в Chrome Canary
О контейнерных запросах запомнилось много шуток, но они, наконец, здесь. Специально к старту нового потока курса по Frontend разработке, делимся с вами статьей, в которой рассказывается зачем нам нужны контейнерные запросы, как они облегчат нашу жизнь, и, самое важное, ваши компоненты и макеты станут мощнее. Если вы взволновались так же, как и я, давайте углубимся в тему. Вы готовы?
Проблема с медиазапросами
Веб-страница состоит из разных разделов и компонентов, которые мы делаем отзывчивыми при помощи медиазапросов CSS. В этом нет ничего плохого, но есть ограничения. Например, мы можем написать медиазапрос, чтобы показать минимальную версию компонента на мобильном или настольном компьютере. Часто отзывчивый веб-дизайн не имеет отношения к видовому экрану или к размеру экрана. Он касается размера контейнера. Рассмотрим такой пример:
Вот очень типичный макет с компонентом — карточкой. И два варианта:
Стопкой (смотрите aside).
Горизонтально (смотрите main).
Реализовать такое на CSS можно несколькими способами, вот самый распространённый: нам нужно создать базовый компонент, а затем написать его вариации.
Это проблема, и мы можем решить её при помощи контейнерных запросов. (Есть! наконец-то!) До погружения в тему давайте взглянем на результат.
Нам нужно сообщить компоненту, что, если непосредственная ширина родительского элемента больше 400 пикселей, ему нужно переключиться на горизонтальный стиль. CSS будет выглядеть так:
Как помогут контейнерные запросы?
Предупреждение: контейнерные запросы CSS пока поддерживаются только в Chrome Canary с экспериментальным флагом.
При помощи контейнерных запросов CSS мы можем решить вышеуказанную проблему и создать растягиваемый компонент. Это означает, что мы можем вложить компонент в узкий родительский элемент, и он превратится в версию «стопкой», а в широком родительском компоненте — в горизонтальную версию. Опять же все элементы не зависят от ширины видового экрана.
Вот как я представляю себе это:
Фиолетовый контур — это ширина родительского компонента. Обратите внимание, как компонент адаптируется к большему размеру своего родительского компонента. Разве это не потрясающе? Вот мощь контейнерных запросов CSS.
Как работают контейнерные запросы
С контейнерными запросами теперь можно поэкспериментировать в Chrome Canary. Чтобы включить их, перейдите в chrome://flags, найдите чекбокс «container queries» и отметьте его.
Сначала добавим свойство contain. Компонент будет адаптироваться под родительскую ширину, поэтому нужно сказать браузеру, чтобы он перерисовал не всю страницу, а только её изменяемую область. Заранее сообщить об этом браузеру мы можем при помощи свойства contain.
Значение inline-size означает, что компонент реагирует только на изменения ширины родительского элемента [прим. перев. — в случае языков с вертикальным направлением, возможно, речь идёт о высоте]. Я попытался задействовать block-size, но это свойство ещё не работает. Пожалуйста, поправьте меня, если я ошибаюсь.
У нас есть следующие стили:
По умолчанию (вид карточки).
Горизонтальная карточка с маленьким предпросмотром.
Горизонтальная карточка с большим предпросмотром.
Если родительский компонент слишком большой, стиль будет похож на стиль раздела hero, указывая, что это избранная статья.
Давайте углубимся в примеры применения контейнерных запросов.
Случаи применения контейнерных запросов CSS
Контейнерные запросы и CSS-грид с auto-fit
В некоторых случаях применение auto-fit в CSS-гриде приводит к неожиданным результатам. Например, компонент оказывается слишком широким, и его содержимое трудно читается. Дам немного контекста: вот визуальный элемент, показывающий разницу между auto-fit и auto-fill в гриде CSS:
Обратите внимание, что при использовании auto-fit элементы расширяются, чтобы заполнить доступное пространство. Однако в случае автоматического заполнения « элементы грида не будут разрастаться, вместо этого у нас будет свободное пространство (пунктирный элемент в крайнем правом углу).
Возможно, вы сейчас думаете, как этот факт относится к контейнерным запросам. Каждый элемент грида — это контейнер, и, когда он расширяется (то есть когда мы используем auto-fit), нам нужно, чтобы компонент изменился, опираясь на это расширение.
Когда элемента четыре, результат должен выглядеть примерно так:
Что произойдёт, когда количество статей уменьшится? Чем меньше у нас будет элементов, тем они будут шире. Так происходит потому, что мы используем auto-fit. Первый выглядит хорошо, но последние два (2 на ряд, 1 на ряд) — не очень: они слишком широкие:
Что делать, если каждый компонент статьи изменяется в зависимости от ширины родительского компонента? Если так, auto-fit будет очень хорошим преимуществом. Вот что нужно сделать: если ширина элемента грида превышает 400 пикселей, статья должна переключиться на горизонтальный стиль, а добиться этого можно так:
Кроме того, если статья — единственный элемент в гриде, хочется отобразить её с разделом hero.
Вот и всё. У нас есть компонент, реагирующий на ширину родительского компонента, и он работает в любом контексте. Разве это не потрясающе? Посмотрите демо на CodePen.
aside и main
Как видно на рисунке, мы работаем с разделом новостей в двух разных контекстах:
Я знаю, что мы можем сказать браузеру, чтобы элементы были обтекающими в случае, когда flexbox не хватает пространства, но этого недостаточно. Мне нужно гораздо больше контроля, чтобы делать кнопку во всю ширину и прятать определённые элементы:
Вот видео с результатом.
Пагинация
Я обнаружил, что контейнерные запросы хорошо подходят для пагинации. Сначала у нас могут быть кнопки “Previous” и “Next”; если пространства достаточно, можно скрыть кнопки и показать всю нумерацию страниц. Посмотрим на рисунок ниже:
Чтобы справиться с приведёнными выше состояниями, сначала нужно поработать над стилем по умолчанию (кнопками в виде стопки), а затем — над двумя другими состояниями.
Карточка профиля
Вот ещё один пример применения: контейнерные запросы идеально работают в нескольких контекстах. Состояние малого размера работает при маленьких видовых экранах и в контекстах вроде сайдбара. Состояние большого размера работает при гораздо больших контекстах, таких как размещение в гриде из двух колонок.
При помощи этого кода теперь мы видим, как компоненты работают в разных контекстах без единого медиазапроса.
Элементы формы
Я ещё не углублялся в случаи применения контейнерных запросов для форм, но в голове держу переключение с горизонтальных меток на метки в стопку.
Посмотрите демо на CodePen.
Тестирование компонентов
Теперь, когда мы рассмотрели несколько случаев, когда контейнерные запросы могут быть полезны, возникает вопрос: как протестировать компонент? К счастью, мы можем сделать это с помощью свойства родительского компонента resize.
Об этом методе я узнал из этой замечательной статьи Брамуса Ван Дамма.
Легко ли отлаживать контейнерные запросы в DevTools?
Короткий ответ — нет. Вы не увидите чего-то вроде @container (min-width: value). Я думаю, что это дело времени, поддержка такой отладки появится.
А запасной вариант для браузеров без контейнерных запросов?
Да! Конечно. Определённым образом можно предоставить альтернативу. Вот две замечательные статьи с объяснением, как это сделать:
Заключение
Мне понравилось изучать контейнерные запросы в CSS и играть с ними в браузере. Я знаю, что они ещё официально не поддерживаются, но сейчас для этого самое время. Часть нашей работы как фронтендеров заключается в том, чтобы тестировать функции браузеров и помогать работающим над их реализацией людям. Чем лучше протестирована экспериментальная функциональность, тем меньше проблем мы увидим, когда она станет поддерживаться во всех основных браузерах.
Если вы уже имеете некоторые навыки работы с CSS, но всё ещё не можете сказать, что разбираетесь во фронтенде — можете обратить внимание на наш курс-профессию Frontend-разработчик, где вы сможете научиться создавать адаптивные веб-сайты с использованием CSS, Flexbox, разрабатывать интерактивные веб-сайты и приложения на JS и HTML, а также писать сложные компоненты на React и интерфейсы с авторизацией и с подключением к бэкенду.
Ну а если фронтенд для вас давно родная стихия — пора смотреть в сторону Fullstack-разработчика, настоящего универсала веб-разработки, которому будут рады в любом крупном проекте.
Узнайте, как прокачаться и в других специальностях или освоить их с нуля:


















