Pull to refresh

Задачка про страницу в три столбца, один из них в сто пикселей

Reading time 6 min
Views 11K
Эта статья задумывалась как небольшое руководство к выполнению лабораторной работы для студентов, начинающих изучать веб-технологии.

Разработать страницу, состоящую из трех разноцветных столбцов. Левый столбец шириной 100 пикселей, центральный и правый занимают все оставшееся до края страницы место равномерно. Высота всех трех 100% страницы. Не должно быть скроллбара и белых полос вокруг страницы.

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

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

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

I вариант


Первый вариант — совсем студенческий. Обычно подобным образом все и выглядело. И по понятным причинам: студент, имея в качестве бэкграунда только понимание общего принципа работы связки технологий HTML+CSS и самых простых CSS-селекторов, наверно, ничего другого и не мог написать.

<body>
  <div class="one"></div>
  <div class="two"></div>
  <div class="three"></div>
</body>

html, body {
  width: 100%;
  height: 100%;
  margin: 0;
  display: flex;
}
.one {
  width: 100px;
  height: 100%;
  background: red;
}
.two {
  width: calc(50% - 50px);
  height: 100%;
  background: green;
}
.three {
  width: calc(50% - 50px);
  height: 100%;
  background: blue;
}

CODEPEN

Причем надо понимать, что некоторые юные программисты слыхом не слыхивали о правилах оформления кода, поэтому его «красота» и читабельность требовали рефакторинга.

Итак, здесь мы имеем несколько антипаттернов: незначащие имена классов, многократное повторение кода, а также отсутствие контейнера и, как следствие, стилизация body. На этом этапе студенты погружались в изучение соглашения по именованию в БЭМ и приципов DRY, DIE, KISS, SOLID, YAGNI.

Хочется отдельно рассказать, почему я запрещаю навешивать стили на body, так как однозначного ответа в сети с первого раза не нашлось. Такое решение пришло из личной практики: изначально в одном из проектов было задано примерно следующее:

body {
  max-width: 1024px;
}

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

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

.red {
  background: red;
}
.green {
  background: green;
}
.blue {
  background: blue;
}

II вариант


Другим самым очевидным оказался вариант раскладки в таблицу. Сыграло свою роль ключевое слово «столбец» в постановке задачи.

<table class="blocks">
  <td class="blocks--block__fixed-width red"></td>
  <td class="blocks--block green"></td>
  <td class="blocks--block blue"></td>
</table>

html, body {
  margin: 0;
  width: 100%;
}
.blocks {
  height: 100vh;
  width: 100%;
  border-collapse: collapse;
}
.blocks--block__fixed-width {
  width: 100px;
}
.blocks--block {
  width: calc(50% - 50px);
}

CODEPEN

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

III вариант


Особенностью следующего варианта является дополнительная обертка для второго и третьего столбца. Эта обертка (wrapper) позволяет проще решать задачу распределения пространства страницы между центральным и правым стобцами без использования возможностей Flexbox Layout.

<div class="blocks">
  <div class="blocks--block__fixed-width red"></div>
  <div class="blocks--wrapper">
    <div class="blocks--block green"></div>
    <div class="blocks--block blue"></div>
  </div>
</div>

html, body {
  margin: 0;
}
.blocks, .blocks--wrapper {
  display: flex;
  height: 100vh;
}
.blocks--wrapper {
  width: calc(100% - 100px);
}
.blocks--block {
  width: 50%;
}
.blocks--block__fixed-width {
  width: 100px;
}

CODEPEN

IV вариант


В следующем примере, во-первых, используются псевдоклассы :first-child и :not(:first-child) для выделения соответственно первого и всех_кроме_первого элементов, имеющих class="block". Во-вторых, используется больше возможостей Flexbox Layout, в частности свойство дочерних элементов flex, которое объединяет свойства flex-grow, flex-shrink и flex-basis и, таким образом, определяет относительные размеры элементов.

<div class="blocks">
  <div class="block red"></div>
  <div class="block green"></div>
  <div class="block blue"></div>
</div>

html, body {
  margin: 0;
}
.blocks {
  display: flex;
  height: 100vh;
}
.block:first-child {
  flex: 0 0 100px;
}
.block:not(:first-child) {
  flex: 1 1 50%;
}

CODEPEN

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

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

<div id="root"></div>

const colours = ['red','blue','green'];

const blocks = colours.map(colour => 
      <div className={"block " + colour}></div>
    );

ReactDOM.render(
  <div className="blocks">{blocks}</div>,
  document.getElementById('root')
);

#root, html, body {
  margin: 0;
}
.blocks {
  display: flex;
  height: 100vh;
  width: 100%;
}
.block:first-child {
  flex: 0 0 100px;
}
.block:not(:first-child) {
  flex: 1 1 50%;
}

CODEPEN

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

V вариант


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

<div class="container"></div>

html, body {
  margin: 0;
}
.container {
  width: 100%;
  height: 100vh;
  background: linear-gradient(
    to right, 
    red 100px, 
    green 100px,
    green calc(50% + 50px),
    blue calc(50% + 50px)
  );
}

CODEPEN

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

VI вариант


В комментарии SmithZx предложил отличное решение на Grid Layout — это очень удобная и современная альтернатива существующим раскладкам. На его основе получилось, наверное, самое лаконичное решение:

<div class="blocks">
  <div class="red"></div>
  <div class="green"></div>
  <div class="blue"></div>
</div>

html, body {
  margin: 0;
}
.blocks {
  display: grid;
  height: 100vh;
  grid-template-columns: 100px 1fr 1fr;
}

CODEPEN

VII вариант


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

<div class="blocks">  
  <div class="block fixed-width red"></div>
  <div class="block green"></div>
  <div class="block blue"></div>
</div>

html, body {
  margin: 0;
}
.blocks {
  display: table;
  width: 100%;
  height: 100vh;
  table-layout: fixed;
}
.block {
  display: table-cell;
  width: 50%;
}
.block.fixed-width {
  width: 100px;
}

CODEPEN

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

VIII вариант


Также очень интересной показалась идея не использовать только display:block, предложенная nebsehemvi в комментарии. Такая необходимость может возникнуть, например, для обеспечения обратной совместимости, так как до сих пор широко используются браузеры не поддерживающие Flexbox и Grid.

<div>  
  <div class="block fixed-width red"></div>  
  <div class="block green"></div>  
  <div class="block blue"></div>  
</div>

html, body {
  margin: 0;
}
.block {
  display: block;
  float: left;
  height: 100vh;
  width: calc((100% - 100px)/2); 
}
.fixed-width {
  max-width: 100px; 
}

CODEPEN

IX вариант


И совсем экстремальный вариант, предложенный dimpa91 в комментарии. Здесь идея состоит в том, чтобы отказаться от функции calc, чтобы летало даже на CCS2.

<div class="blocks">
  <div class="block fixed-width red"></div>  
    <div class="block green"></div>
    <div class="block blue"></div>
</div>

body, html {
  margin: 0;
}
.blocks {
  margin-left: 100px;
}
.block.fixed-width {
  width: 100px;
  margin-left: -100px;
}
.block {
  width: 50%;
  height: 100vh;
  float: left;
}

CODEPEN

Спасибо всем, кто выразил свое профессиональное мнение и отдельное большое спасибо тем, кто проиллюстрировал его кодом! Всем лучи добра .)
Tags:
Hubs:
+9
Comments 27
Comments Comments 27

Articles