Химия CSS-гридов

На StackOverflow один участник задал вопрос, как сверстать на CSS Grid периодическую таблицу Менделеева. Примеров периодических таблиц на гридах в Сети навалом, есть и очень симпатичные. Но чаще всего они стремятся воспроизвести лишь внешний вид таблицы, порой вручную расставляя элементы по клеткам.

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

Химические элементы как грид-элементы

Как мы помним со школьных лет, периодический закон в химии вытекает из строения электронных орбиталей, описываемых квантовыми числами… Шучу, ничего из этого нам не понадобится:). Нам важен результат. Есть система элементов — упорядоченный их набор. Она периодическая: через определенные промежутки чисел свойства элементов повторяются. Элементы с похожими свойствами стоят друг под другом. Сравним с грид-элементами: они тоже идут друг за другом по порядку, заполняя ряд за рядом, элементы следующего ряда располагаются точно под элементами предыдущего. Один в один!

Одна загвоздка: если в гриде у нас все «периоды» (длины рядов) равны, то в химии следующие периоды бывают длиннее предыдущих (последовательность такая: 2, 8, 8, 18, 18, 32, 32). Не беда: возьмем число колонок по максимуму (32 шт.), а нужные элементы просто подвинем в нужную колонку. Поскольку алгоритм авторазмещения по умолчанию не заполняет пропуски, остальные элементы будут сами идти за ними по порядку, как обычно.

Что ж, за дело. Берем упорядоченный список всех 118 известных на сегодня элементов и укладываем его в грид с 32 колонками и автоматическим количеством рядов равной высоты:

.periodic {
  display: grid;
  grid-template-columns: repeat(32, 1fr);
  grid-auto-rows: 1fr;
}

Периодичность химических элементов лучше всего прослеживается «с конца». Инертные газы (2-й, 10-й, 18-й, 36-й и т.д. элементы) должны стоять в последней колонке. Вспоминаем, что последняя колонка в гридах — это от предпоследней грид-линии до последней. Значит, началом нужной колонки будет вторая грид-линия, считая с конца, т.е. линия с номером -2. Для начала поставим туда гелий:

.element:nth-child(2) {
  grid-column: -2;
}

Теперь надо выстроить галогены (9-й, 17-й, 35-й и т.д. элементы) под галогенами, азот, фосфор и т.д. — в свою колонку, углерод, кремний и т.д. — в свою… в общем, 6-й с конца элемент каждого периода должен стоять в 6-й с конца колонке, и остальные (включая все оставшиеся инертные газы) сами станут, как надо. Причем фактически нам надо подвинуть туда только элементы 2 и 3 периодов — бор и алюминий. Потому что элементы следующих периодов сами встанут как надо, после того, как мы подвинем титан, цирконий, гафний и резерфордий (элементы № 22, 40, 72 и 104) в 15-ю с конца колонку. Точнее, именно двигать надо только 22-й и 40-й, ведь два последних периода заполнены до отказа:

.element:nth-child(-8n + 13) { /* элементы 5 и 13 */
  grid-column: -7;
}

.element:nth-child(22),
.element:nth-child(40) {
  grid-column: -16;
}

Периодическая таблица готова! Понадобилось всего 3 особых правила для 5 элементов, остальное нам сделал алгоритм авторазмещения. Вот что значит использовать законы природы и особенности технологии, а не бороться с ними! :)

Элементы реагируют

Но такая «растянутая» форма таблицы Менделеева удобна разве что для больших и при этом очень низких окон (скажем, на широкоформатном мониторе с соотношением 21:9).

Поэтому наши элементы, как и в химии, должны реагировать:) — как минимум на размер и пропорции окна. И для меньших размеров и более привычных пропорций показывать таблицу в более привычном виде, с 18 колонками и отдельно вынесенными семействами лантаноидов (элементы 58-71) и актиноидов (элементы 90-103).

И снова сама природа периодического закона идет нам навстречу: поскольку мы отсчитывали положение ячеек от конца грида, правая сторона таблицы останется в порядке и при 18 колонках до самого ксенона включительно! Дальше, правда, порядок сбивается, но сейчас мы его восстановим. Нам надо выбрать элементы 58-71 и «отпихнуть» их в другое место, чтоб не мешали. И оставшиеся элементы (72-й и далее) продолжат свой порядок как ни в чем не бывало — опять же, так работает периодический закон, и так работает алгоритм авторазмещения!

Выбирать элементы «с такого-то по сякой-то» мы умеем:

.element:nth-child(n + 58):nth-child(-n + 71) {
  grid-row: 9;
}

Автоматически у нас заполнены 7 рядов грида, так что 8-й и ниже — полностью в нашем распоряжении (пока не начали открывать элементы 8 периода:). На всякий случай — и просто для красоты — оставляем между основной таблицей и добавочной строкой один ряд пропуска.

Опять же на всякий случай, чтобы читатели не удивлялись, что это у нас за «вырванный» из основной последовательности кусок, можно его подписать. Я подумал, что поскольку такая перестройка таблицы у нас — это смена оформления, то и подписать можно силами оформления, силами CSS. Идея спорная, признаю, ценители доступности могут меня… не понять. Но зато она показывает нам еще одну возможность CSS-гридов, о которой вы, может быть, не  задумывались:

.periodic::before {
  content: 'Лантаноиды';
  grid-row: 8;
  grid-column: 1/-1;
  align-self: end;
}

Да, псевдоэлементы ::before и ::after грид-контейнера — тоже полноценные грид-элементы, и их можно ставить в любое место грида! И даже растягивать на любое число ячеек, хоть от края до края (как здесь).

С элементами 90-103 поступаем аналогично. Как раз остался второй псевдоэлемент, чтобы их подписать:). На всё потребовалось 4 дополнительных правила (и то два — вспомогательные, необязательные).

Элементы при сжатии

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

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

Выглядит такая таблица похитрее: у нее вроде как 8 колонок, но в некоторых строках, начиная с 4-й — по 10 ячеек. Ничего, гриды умеют и такое! Делаем грид на 8 колонок, правило с 16-й с конца колонкой (которой больше нет) отменяем, и заставляем элементы первой группы (те самые металлы) начинаться с первой колонки, снова используя периодичность:

.periodic {
  grid-template-columns: repeat(8, 1fr);
  grid-auto-columns: 1fr;
}

.element:nth-child(22),
.element:nth-child(40) {
  grid-column: auto;
}
  
.element:nth-child(3),
.element:nth-child(-18n + 29), /* элементы 11 и 29 */
.element:nth-child(-18n + 37), /* элементы 19, 37 и 1 (не помешает:) */
.element:nth-child(32n + 47),  /* элементы 47, 79 и 111 */
.element:nth-child(32n + 55) { /* элементы 55, 87 и еще не открытый 119 */
  grid-column: 1;
}

Теперь надо сделать, чтобы «хвосты» длинных периодов (строки, в которых должно быть 10 ячеек) не загибались. Можно, конечно, расставить эти 12 элементов вручную… но можно воспользоваться силой магии науки:

.periodic::after {
  grid-column-end: 11;
}

…просто взяли и растянули грид-элемент не до последней, а до 11-й грид-линии!

Откуда в восьмиколоночном гриде 11-я линия (т.е. 10-я колонка)? Не забываем про неявный грид, что ряды и колонки могут автоматически создаваться «по надобности». Свойство grid-auto-columns делает их ширину такой же, как у явных. А алгоритм авторазмещения стремится заполнить весь фактический грид, неважно, явный или неявный, так что «лишние» ячейки как раз сами станут в нужные нам добавочные колонки.

Что мешало сразу сделать 10 колонок, раз все они нам нужны, а не химичить с добавлением двух неявных? В принципе, ничего. Но тогда нам пришлось бы опять явно двигать гелий — ведь он у нас стоит в последней явной колонке. А так он сразу оказался именно там, где надо, над неоном и прочими собратьями.

Осталось опустить лантаноиды с актиноидами на 4 ряда вниз, и для компактности вывести каждое семейство в 2 строки вместо одной (никакой особой химии здесь нет, код аналогичен тому, что мы уже видели). Над этой формой таблицы пришлось потрудиться побольше — не зря она устарела, признана искусственной, не вытекающей из законов природы напрямую, как предыдущие:). Еще пара последних штрихов — и можно смотреть…

Результат

Желательно открыть в отдельном окне, чтоб можно было поменять его размеры и пропорции, включая широкую и низкую горизонтальную «щель»:

See the Pen Отзывчивая периодическая система элементов на CSS Grid by Ilya Streltsyn (@SelenIT) on CodePen.

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

P.S. К сожалению, автор того вопроса на StackOverflow вместо того, чтобы воспользоваться силой знания законов природы, выбрал какое-то негибкое и костыльное решение на дивах-распорках. Не будьте как он:)

P.S. Это тоже может быть интересно:

2

Комментарии

  1. Алексей

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

    Ну сначала, конечно, подробно сформулировать задачу. Расписать, чтоб было ясно что и где должно отображаться. Возможно, какие-то отдельные элементы, можно конкретизировать во время реализации А потом. Разместите элементы в гридах. Запихните с такого-то по такой-то элементы туда-то… И так далее.

    Можно сделать несколько вариантов решения. Можно сделать разные «уровень поддержки». Да много идей, наверное, могут возникнуть, по-ходу дела…

  2. Мирослав

    Круто =))))

Оставить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Ваш E-mail не будет опубликован

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