Адаптивная турнирная сетка на CSS3
Дело было в пятницу вечером, на любимом форуме нашелся интересный вопрос, на jsFiddle нашлось место для экспериментов. В итоге получилось вот что:
Желательно смотреть в отдельном окне.
Предупреждаю, что сделано это исключительно ради пробы технологии («proof of concept», как говорят «у них»). Чтобы использовать на практике, нужно будет много чего подшлифовать под себя. Но даже этот вариант достаточно гибок: размеры блоков не фиксированы и определяются контентом, раунды турнира (уровни вложенности) можно добавлять и убавлять, и сетка будет строиться автоматически. И оба варианта раскладки сетки подстраиваются под ширину окна/колонки.
Буквально в двух словах о том, как это работает. Очевидно, что основную «магию» делают наши любимые флексбоксы (по которым мы не так давно переводили и чуть исправляли наглядную шпаргалку). Интересных моментов здесь, на мой взгляд, два (может, даже два с половиной:), и оба они касаются линий между блоками. Линии сделаны из псевдоэлементов ::before
и ::after
, причем эти псевдоэлементы всегда находятся между дочерними элементами (в нашем случае — абзацем и вложенным списком). Раньше это было невозможно в CSS, ведь псевдоэлементы вставляются только в начало и конец элемента, до и после контента. Но во Flex-раскладке есть замечательное свойство order
, которое позволяет менять порядок любых флекс-элементов — хоть обычных DOM-элементов, хоть сгенерированных. Оно-то и помогло переместить псевдоэлементы в середину.
Второй относительно интересный момент — рисование «вилок», соединяющих соперников по матчам. Здесь нам на помощь приходят CSS-градиенты, background-size
(превращающий градиент в тонкую линию нужной нам длины) и background-position
, о котором у нас недавно тоже был материал. А также тот удобный факт, что по умолчанию флекс-элементы растягиваются на всю высоту контейнера, так что нам легко отмерить четверть от верха и низа. «Вилка» состоит из трех линий, поэтому все свойства — в трех экземплярах.
Ну и «половина» интересного момента — превращение вертикальных флексбоксов для «финалистов» в горизонтальные при достаточной для этого ширине окна (и соответствующее «отзеркаливание» вилок). Тут всё должно быть понятно из кода (который, подозреваю, можно еще и неплохо оптимизировать, так что добро пожаловать в комменты!).
Разметка же минималистична и, на мой взгляд, неплохо отражает логику контента: вложенные группы, объединенные по парам, для каждой из которых определен единственный победитель. Я поставил «победителя» после группы (как итог соотв. встречи), но его можно вынести и вперед, как заголовок — на отображении это не скажется (еще один плюс флексбоксов и свойства order
!). По-моему, получившаяся структура достаточно понятна даже сама по себе (при минимальной ширине окна можно увидеть ее практически в «голом» виде — честно говоря, у меня просто закончилась фантазия, чтобы оформить это как-нибудь заковыристо, но для учебного примера в таком минимализме есть даже плюс:).
P.S. Не претендую на то, что мне первому пришла в голову подобная идея (как минимум, был прецедент с полгода назад), но всё же моя реализация показалась мне достойной того, чтоб ей поделиться).
P.S. Это тоже может быть интересно:
Я вот так делала http://shpargalkablog.ru/2014/12/tabletree.html#horizontal без флексов, растягивается под содержимое
Здорово! Очень впечатляющая демонстрация возможностей табличного отображения CSS. Особенно сейчас, когда проблема абсолютного позиционирования в ячейках больше не актуальна. Спасибо за лаконичный и полезный пример в копилку!
Я тоже оглядывалась на позиционирование в ячейках :)
Вот так еще чуваки умеют — http://codepen.io/jbeason/pen/Wbaedb
Да, похоже, идея «схлопывания» горизонтальной раскладки в вертикальную при сужении окна носится в воздухе:). Хотя это логичное поведение, а флекбоксы позволяют очень легко его реализовать. Спасибо за пример!
Большое спасибо за Ваш материал. Очень полезен.
Но есть одно но. Если текст внутри p тегов имеет разную длину, красивая пирамида становится немного кривой.
Пример здесь: https://jsfiddle.net/samouchka/cepu7sfj/2/ Можно ли как-то избежать такого поведения, ведь в реальном турнире имена победителя имеют разную длину.
Можно ограничить растягиваемость/сжимаемость элементов (flex-grow/flex-shrink) и поиграть с этими параметрами для разных уровней пирамиды (набросок навскидку: https://jsfiddle.net/wh2yatz6/1/). Исходный пример был больше для иллюстрации общего принципа…