[{"data":1,"prerenderedAt":2258},["ShallowReactive",2],{"topic:aidt-mag-frontend:topic-03":3},{"content":4,"pz":1935,"lr":1935,"additional":1945,"courseMeta":2177},{"id":5,"title":6,"body":7,"course_slug":1933,"description":1934,"env_label":1935,"env_url":1935,"extension":1936,"group":1935,"is_course_project":1937,"is_index":1937,"level":1935,"meta":1938,"navigation":1564,"path":1939,"section":1940,"seo":1941,"stem":1942,"topic_number":835,"topic_slug":1943,"__hash__":1944},"courses\u002Fcourses\u002Faidt-mag-frontend\u002Ftopic-03-content.md","Тема 3. Layout: позиционирование, Flexbox, Grid, адаптивность",{"type":8,"value":9,"toc":1893},"minimark",[10,14,28,33,38,68,85,107,120,123,143,159,183,198,223,227,245,271,291,295,316,348,354,364,379,385,398,407,414,423,463,469,481,490,494,498,519,551,560,573,626,642,658,671,674,707,713,784,795,799,802,808,871,880,952,961,965,969,990,1018,1027,1034,1118,1141,1148,1177,1188,1331,1337,1350,1365,1435,1449,1453,1456,1466,1469,1473,1477,1488,1492,1513,1674,1684,1688,1695,1719,1775,1778,1782,1821,1828,1832,1844,1847,1851,1889],[11,12,6],"h1",{"id":13},"тема-3-layout-позиционирование-flexbox-grid-адаптивность",[15,16,17,18,22,23,27],"p",{},"В теме 1 мы описали структуру документа, в теме 2 — оформление отдельных элементов: цвет, шрифт, размеры коробки. Но интерфейс — это не набор независимо оформленных блоков, а их взаимное расположение на плоскости: колонки рядом, шапка сверху, карточки сеткой, боковая панель, прижатая к краю. За это отвечает раскладка (англ. ",[19,20,21],"em",{},"layout",") — совокупность механизмов CSS, определяющих, где именно окажется каждый элемент. Раскладка — та часть CSS, которая исторически менялась сильнее всего: от табличной вёрстки девяностых через ",[24,25,26],"code",{},"float"," к специально спроектированным Flexbox и Grid. Мы разберём её послойно — от потока документа, работающего по умолчанию, к позиционированию, затем к двум современным модулям раскладки, и завершим адаптивностью: тем, как одна вёрстка обслуживает экраны от телефона до широкого монитора.",[29,30,32],"h2",{"id":31},"поток-документа-и-модели-отображения","Поток документа и модели отображения",[34,35,37],"h3",{"id":36},"нормальный-поток-блочные-и-строчные-контексты","Нормальный поток: блочные и строчные контексты",[15,39,40,41,45,46,49,50,63,64,67],{},"Пока к элементам не применены никакие свойства раскладки, браузер размещает их в ",[42,43,44],"strong",{},"нормальном потоке"," (англ. ",[19,47,48],{},"normal flow",") — порядке по умолчанию, заданном спецификацией ",[51,52,55],"sup",{"className":53},[54],"cite",[56,57,59],"a",{"href":58},"#ref-1",[60,61,62],"span",{},"1",". Правило потока простое и предсказуемое: элементы идут в том же порядке, в каком записаны в разметке, и каждый следующий встаёт после предыдущего. Различие в том, ",[19,65,66],{},"как"," именно встаёт, — и здесь работают два контекста.",[15,69,70,73,74,77,78,77,81,84],{},[42,71,72],{},"Блочные элементы"," (",[24,75,76],{},"\u003Cdiv>",", ",[24,79,80],{},"\u003Cp>",[24,82,83],{},"\u003Csection>",", заголовки) выстраиваются сверху вниз, каждый с новой строки, и по умолчанию занимают всю доступную ширину родительского элемента — сколько бы места ни требовало содержимое. Два абзаца подряд окажутся один под другим, даже если в каждом всего одно слово.",[15,86,87,73,90,77,93,77,96,77,99,102,103,106],{},[42,88,89],{},"Строчные элементы",[24,91,92],{},"\u003Cspan>",[24,94,95],{},"\u003Ca>",[24,97,98],{},"\u003Cem>",[24,100,101],{},"\u003Cstrong>",") выстраиваются слева направо внутри строки, как слова в тексте, и переносятся на следующую строку только когда заканчивается место. Их ширина и высота определяются содержимым; задать им ",[24,104,105],{},"width"," или вертикальные отступы напрямую нельзя — это одно из типичных мест, где начинающий разработчик безуспешно пытается «раздвинуть» строчный элемент.",[108,109,110,111,110,116],"figure",{},"\n  ",[112,113],"img",{"src":114,"alt":115},"\u002Fimg\u002Faidt-mag-frontend\u002Ftopic-03\u002Fnormal_flow.svg","Нормальный поток: блочные элементы во всю ширину друг под другом, строчные — в ряд с переносом",[117,118,119],"figcaption",{},"Блочный и строчный контекст нормального потока",[15,121,122],{},"Нормальный поток — не архаизм, который нужно поскорее отключить, а разумная основа. Большая часть текстового контента прекрасно раскладывается именно им, и хорошая вёрстка обычно оставляет поток работать там, где он справляется, вмешиваясь только там, где нужна нестандартная геометрия.",[34,124,126,127,130,131,77,134,77,137,77,140],{"id":125},"свойство-display-block-inline-inline-block-none","Свойство ",[24,128,129],{},"display",": ",[24,132,133],{},"block",[24,135,136],{},"inline",[24,138,139],{},"inline-block",[24,141,142],{},"none",[15,144,145,146,148,149,158],{},"К какому контексту относится элемент, определяет не только его тег, но и свойство ",[24,147,129],{},", которое можно переназначить ",[51,150,152],{"className":151},[54],[56,153,155],{"href":154},"#ref-2",[60,156,157],{},"2",". Четыре его базовых значения стоит знать наизусть.",[15,160,161,164,165,77,167,170,171,174,175,178,179,182],{},[24,162,163],{},"display: block"," делает элемент блочным: новая строка, полная ширина, работают ",[24,166,105],{},[24,168,169],{},"height",", вертикальные отступы. ",[24,172,173],{},"display: inline"," — строчным: элемент течёт в строке, игнорирует заданные ширину и высоту. ",[24,176,177],{},"display: none"," полностью убирает элемент из потока и из отрисовки — он не занимает места и недоступен, как будто его нет в разметке (в отличие от ",[24,180,181],{},"visibility: hidden",", который прячет элемент, но оставляет занятое им место).",[15,184,185,186,189,190,77,192,194,195,197],{},"Отдельного внимания заслуживает ",[24,187,188],{},"display: inline-block"," — гибрид, который течёт в строке рядом с соседями, как строчный, но при этом принимает ",[24,191,105],{},[24,193,169],{}," и вертикальные отступы, как блочный. Долгое время ",[24,196,139],{}," был рабочей лошадкой для раскладки горизонтальных рядов — кнопок, пунктов меню, карточек, — пока эту роль не переняли Flexbox и Grid. Сегодня его основное применение — точечное: элемент, который должен вести себя как слово в тексте, но с заданными габаритами.",[15,199,200,201,203,204,207,208,211,212,214,215,218,219,222],{},"Значения ",[24,202,129],{}," этим не исчерпываются: ",[24,205,206],{},"flex"," и ",[24,209,210],{},"grid",", которым посвящены отдельные разделы темы, тоже задаются через это свойство. Формально ",[24,213,129],{}," управляет сразу двумя вещами — тем, как элемент ведёт себя ",[19,216,217],{},"снаружи"," (блочный или строчный по отношению к соседям), и тем, какой контекст раскладки он создаёт ",[19,220,221],{},"внутри"," для своих потомков.",[34,224,226],{"id":225},"контекст-форматирования-и-сворачивание-полей","Контекст форматирования и сворачивание полей",[15,228,229,230,45,233,236,237,244],{},"Контейнер с блочными потомками создаёт вокруг них ",[42,231,232],{},"блочный контекст форматирования",[19,234,235],{},"block formatting context",", BFC) — изолированную область, внутри которой действуют правила блочного потока ",[51,238,240],{"className":239},[54],[56,241,242],{"href":58},[60,243,62],{},". Понятие звучит абстрактно, но за ним стоят вполне ощутимые эффекты, и один из них мы уже встречали.",[15,246,247,248,251,252,45,255,258,259,262,263,266,267,270],{},"В теме 2, разбирая блочную модель, мы отметили, что вертикальные ",[24,249,250],{},"margin","-ы соседних блоков ",[42,253,254],{},"схлопываются",[19,256,257],{},"margin collapsing","): при ",[24,260,261],{},"margin-bottom: 20px"," у одного блока и ",[24,264,265],{},"margin-top: 30px"," у следующего промежуток окажется 30 px, а не 50. Теперь можно назвать причину: схлопывание — свойство именно блочного контекста форматирования, в котором соприкасающиеся вертикальные поля объединяются в одно, равное большему из них. Схлопываются и поля вложенных элементов с полями родителя, если между ними нет рамки, padding-а или содержимого, — из-за чего ",[24,268,269],{},"margin-top"," дочернего элемента иногда «протекает» наружу и сдвигает весь родительский блок.",[15,272,273,274,277,278,77,281,284,285,287,288,290],{},"Новый BFC создаётся не всегда, а при определённых условиях: у элемента задан ",[24,275,276],{},"overflow"," отличный от ",[24,279,280],{},"visible",[24,282,283],{},"display: flow-root",", он является flex- или grid-элементом, плавает через ",[24,286,26],{},". Внутри такого контекста поля больше не схлопываются с внешними, а плавающие элементы не выходят за его границы. ",[24,289,283],{}," — современное и наименее побочное средство завести чистый BFC, когда нужно, например, чтобы родитель охватывал вложенные плавающие элементы или чтобы прекратить нежелательное схлопывание.",[29,292,294],{"id":293},"позиционирование","Позиционирование",[34,296,298,130,301,77,304,77,307,77,310,77,313],{"id":297},"position-static-relative-absolute-fixed-sticky",[24,299,300],{},"position",[24,302,303],{},"static",[24,305,306],{},"relative",[24,308,309],{},"absolute",[24,311,312],{},"fixed",[24,314,315],{},"sticky",[15,317,126,318,320,321,77,324,77,327,77,330,333,334,343,344,347],{},[24,319,300],{}," выводит элемент из-под управления нормального потока и позволяет задавать его положение явно, через смещения ",[24,322,323],{},"top",[24,325,326],{},"right",[24,328,329],{},"bottom",[24,331,332],{},"left"," ",[51,335,337],{"className":336},[54],[56,338,340],{"href":339},"#ref-3",[60,341,342],{},"3",". У него пять значений, и различаются они тем, ",[19,345,346],{},"относительно чего"," отсчитывается положение.",[15,349,350,353],{},[24,351,352],{},"position: static"," — значение по умолчанию: элемент в нормальном потоке, смещения игнорируются. Это «выключенное» позиционирование.",[15,355,356,359,360,363],{},[24,357,358],{},"position: relative"," оставляет элемент в потоке (место под него сохраняется), но позволяет сместить его визуально относительно исходного положения. Само по себе относительное позиционирование применяют нечасто; куда важнее его побочная роль — оно делает элемент ",[19,361,362],{},"точкой отсчёта"," для абсолютно позиционированных потомков.",[15,365,366,369,370,372,373,375,376,378],{},[24,367,368],{},"position: absolute"," полностью извлекает элемент из потока — соседи смыкаются, как будто его нет, — и позиционирует его относительно ближайшего предка, у которого ",[24,371,300],{}," отличен от ",[24,374,303],{},". Если такого предка нет, отсчёт идёт от корневого блока страницы. Отсюда устойчивый приём: родителю ставят ",[24,377,358],{},", чтобы «поймать» абсолютно позиционированного потомка внутри своих границ. Так размещают бейджи на карточках, кнопки закрытия в углу модального окна, подсказки.",[15,380,381,384],{},[24,382,383],{},"position: fixed"," тоже извлекает элемент из потока, но привязывает его к вьюпорту — видимой области окна. Такой элемент остаётся на месте при прокрутке страницы; типичные применения — «липкая» шапка, кнопка «наверх», плавающая панель действий.",[15,386,387,390,391,393,394,397],{},[24,388,389],{},"position: sticky"," — гибрид относительного и фиксированного. Пока элемент в пределах видимости прокручивается обычным образом (как ",[24,392,306],{},"), но при достижении заданного порога (",[24,395,396],{},"top: 0",") «прилипает» к краю и держится там, пока родительский контейнер не уйдёт из виду. Это поведение заголовков разделов в длинных списках, которые остаются на виду, пока листаешь свой раздел, и уступают место следующему.",[108,399,110,400,110,404],{},[112,401],{"src":402,"alt":403},"\u002Fimg\u002Faidt-mag-frontend\u002Ftopic-03\u002Fpositioning_schemes.svg","Схемы позиционирования: relative со смещением и сохранённым местом, absolute вне потока, sticky у края",[117,405,406],{},"Поведение `relative`, `absolute` и `sticky` относительно потока",[34,408,410,411],{"id":409},"контекст-наложения-и-z-index","Контекст наложения и ",[24,412,413],{},"z-index",[15,415,416,417,419,420,422],{},"Как только элементы перестают идти строго друг за другом и начинают перекрываться, возникает вопрос: какой из них окажется сверху? Порядок наложения регулируется свойством ",[24,418,413],{}," — целым числом, задающим положение элемента по воображаемой оси, направленной от экрана к зрителю. Больший ",[24,421,413],{}," — ближе к зрителю, поверх остальных.",[15,424,425,426,428,429,45,432,435,436,439,440,442,443,445,446,449,450,77,453,77,456,459,460,462],{},"Тонкость в том, что ",[24,427,413],{}," действует не глобально, а внутри ",[42,430,431],{},"контекста наложения",[19,433,434],{},"stacking context",") — изолированной группы, порядок внутри которой считается отдельно. Элемент с ",[24,437,438],{},"z-index: 9999"," внутри одного контекста никогда не перекроет элемент из другого контекста, который стоит выше по дереву, — сколько бы девяток мы ни приписали. Новый контекст наложения создаётся не только через ",[24,441,300],{}," с ненулевым ",[24,444,413],{},", но и рядом других свойств: ",[24,447,448],{},"opacity"," меньше единицы, ",[24,451,452],{},"transform",[24,454,455],{},"filter",[24,457,458],{},"will-change",". Это частый источник недоумения: разработчик поднимает ",[24,461,413],{}," до астрономических значений, а элемент всё равно оказывается под соседом — потому что проблема не в величине, а в том, что они в разных контекстах. Понимание границ контекста наложения устраняет большую часть подобных «магических» багов.",[34,464,466,468],{"id":465},"float-как-устаревающий-механизм",[24,467,26],{}," как устаревающий механизм",[15,470,126,471,473,474,476,477,480],{},[24,472,26],{}," изначально решало узкую типографскую задачу — обтекание изображения текстом, как в бумажной вёрстке. Плавающий элемент сдвигается к краю контейнера, а последующий контент обтекает его сбоку. На безрыбье доспециализированных модулей раскладки ",[24,475,26],{}," два десятилетия использовали не по прямому назначению — для построения многоколоночных сеток, выстраивания элементов в ряд, вёрстки целых страниц. Приём работал, но требовал костылей: очистки обтекания (",[24,478,479],{},"clear",", «clearfix»-хаки), борьбы со схлопыванием высоты контейнера, ручного расчёта ширин в процентах.",[15,482,483,484,486,487,489],{},"С появлением Flexbox и Grid эта роль ",[24,485,26],{}," отмерла: то, ради чего его выкручивали, теперь решается напрямую и без побочных эффектов. За ",[24,488,26],{}," осталась исходная, честная задача — обтекание врезки текстом. В новом коде использовать его для раскладки нет причин, но знать о нём необходимо: он до сих пор встречается в старых кодовых базах, и понимание его механики нужно, чтобы такой код читать и переписывать.",[29,491,493],{"id":492},"flexbox-одномерный-layout","Flexbox: одномерный layout",[34,495,497],{"id":496},"главная-и-поперечная-оси-контейнер-и-элементы","Главная и поперечная оси, контейнер и элементы",[15,499,500,501,504,505,514,515,518],{},"Flexbox (полное название — ",[19,502,503],{},"CSS Flexible Box Layout",") — первый из двух современных модулей, спроектированных специально для раскладки ",[51,506,508],{"className":507},[54],[56,509,511],{"href":510},"#ref-4",[60,512,513],{},"4",". Его назначение — распределять элементы вдоль ",[42,516,517],{},"одной"," оси: в ряд или в столбец. Одномерность — ключевая характеристика: Flexbox управляет раскладкой по одному направлению, оставляя перпендикулярное на втором плане.",[15,520,521,522,525,526,45,529,532,533,45,536,539,540,130,543,546,547,550],{},"Раскладка включается объявлением ",[24,523,524],{},"display: flex"," на контейнере. Его прямые потомки автоматически становятся флекс-элементами и выстраиваются вдоль ",[42,527,528],{},"главной оси",[19,530,531],{},"main axis","); перпендикулярная ей — ",[42,534,535],{},"поперечная ось",[19,537,538],{},"cross axis","). Направление главной оси задаёт свойство ",[24,541,542],{},"flex-direction",[24,544,545],{},"row"," (по умолчанию, слева направо) или ",[24,548,549],{},"column"," (сверху вниз). Всё поведение флекс-контейнера описывается в терминах этих двух осей, поэтому с них и стоит начинать: сначала определить, где главная ось, а затем читать остальные свойства как распределение вдоль неё и поперёк неё.",[108,552,110,553,110,557],{},[112,554],{"src":555,"alt":556},"\u002Fimg\u002Faidt-mag-frontend\u002Ftopic-03\u002Fflexbox_axes.svg","Флекс-контейнер: главная ось с justify-content, поперечная ось с align-items",[117,558,559],{},"Оси Flexbox и свойства выравнивания вдоль каждой из них",[34,561,563,564,77,567,77,570],{"id":562},"свойства-распределения-justify-content-align-items-gap","Свойства распределения: ",[24,565,566],{},"justify-content",[24,568,569],{},"align-items",[24,571,572],{},"gap",[15,574,575,576,578,579,582,583,586,587,590,591,594,595,77,598,77,601,604,605,607,608,611,612,77,614,77,616,77,618,621,622,625],{},"Два свойства управляют выравниванием, и различаются они осью. ",[24,577,566],{}," распределяет элементы ",[42,580,581],{},"вдоль главной оси",": прижать к началу (",[24,584,585],{},"flex-start","), к концу (",[24,588,589],{},"flex-end","), по центру (",[24,592,593],{},"center","), разложить с равными промежутками (",[24,596,597],{},"space-between",[24,599,600],{},"space-around",[24,602,603],{},"space-evenly","). ",[24,606,569],{}," выравнивает элементы ",[42,609,610],{},"поперёк",", по поперечной оси: ",[24,613,585],{},[24,615,589],{},[24,617,593],{},[24,619,620],{},"stretch"," (растянуть на всю высоту контейнера — значение по умолчанию), ",[24,623,624],{},"baseline"," (по базовой линии текста).",[15,627,628,629,631,632,634,635,638,639,641],{},"Держать в голове, какое свойство по какой оси работает, проще всего через привязку к назначению, а не к слову: ",[24,630,566],{}," — «главная», ",[24,633,569],{}," — «поперечная». При ",[24,636,637],{},"flex-direction: column"," оси меняются местами, и теперь уже ",[24,640,566],{}," управляет вертикалью — это регулярно сбивает с толку, пока не привыкнешь думать осями, а не «горизонталью и вертикалью».",[15,643,644,645,647,648,650,651,653,654,657],{},"Промежутки между элементами задаёт свойство ",[24,646,572],{},". До него интервалы приходилось расставлять через ",[24,649,250],{}," на самих элементах, что порождало возню с крайними элементами (лишний отступ у первого или последнего). ",[24,652,572],{}," добавляет промежутки только ",[19,655,656],{},"между"," элементами, не по краям, и работает как во Flexbox, так и в Grid — это одно из самых удобных приобретений современного CSS.",[34,659,661,77,664,77,667,670],{"id":660},"flex-grow-flex-shrink-flex-basis-реакция-на-переполнение",[24,662,663],{},"flex-grow",[24,665,666],{},"flex-shrink",[24,668,669],{},"flex-basis",": реакция на переполнение",[15,672,673],{},"«Flexible» в названии — про способность элементов растягиваться и сжиматься, деля свободное или недостающее место. Поведением каждого элемента управляют три свойства.",[15,675,676,678,679,681,682,685,686,689,690,692,693,695,696,699,700,702,703,706],{},[24,677,669],{}," задаёт базовый размер элемента вдоль главной оси до перераспределения — своего рода стартовую ширину (или высоту в колонке). ",[24,680,663],{}," — коэффициент, с которым элемент забирает ",[19,683,684],{},"избыток"," свободного места: при ",[24,687,688],{},"flex-grow: 0"," (по умолчанию) элемент не растягивается, при ",[24,691,62],{}," — растёт, деля излишек с другими растущими элементами пропорционально их коэффициентам. ",[24,694,666],{}," — зеркальный коэффициент сжатия при ",[19,697,698],{},"нехватке"," места: при ",[24,701,62],{}," (по умолчанию) элемент сжимается, при ",[24,704,705],{},"0"," — сохраняет размер, отказываясь ужиматься.",[15,708,709,710,712],{},"На практике эти три свойства почти всегда задают одной сокращённой записью ",[24,711,206],{},":",[714,715,720],"pre",{"className":716,"code":717,"language":718,"meta":719,"style":719},"language-css shiki shiki-themes github-light github-dark",".sidebar { flex: 0 0 240px; }  \u002F* не растёт, не сжимается, ровно 240px *\u002F\n.content { flex: 1 1 auto; }   \u002F* забирает всё оставшееся место *\u002F\n","css","",[24,721,722,758],{"__ignoreMap":719},[60,723,726,730,734,737,739,741,744,747,751,754],{"class":724,"line":725},"line",1,[60,727,729],{"class":728},"sScJk",".sidebar",[60,731,733],{"class":732},"sVt8B"," { ",[60,735,206],{"class":736},"sj4cs",[60,738,130],{"class":732},[60,740,705],{"class":736},[60,742,743],{"class":736}," 0",[60,745,746],{"class":736}," 240",[60,748,750],{"class":749},"szBVR","px",[60,752,753],{"class":732},"; }  ",[60,755,757],{"class":756},"sJ8bj","\u002F* не растёт, не сжимается, ровно 240px *\u002F\n",[60,759,761,764,766,768,770,772,775,778,781],{"class":724,"line":760},2,[60,762,763],{"class":728},".content",[60,765,733],{"class":732},[60,767,206],{"class":736},[60,769,130],{"class":732},[60,771,62],{"class":736},[60,773,774],{"class":736}," 1",[60,776,777],{"class":736}," auto",[60,779,780],{"class":732},"; }   ",[60,782,783],{"class":756},"\u002F* забирает всё оставшееся место *\u002F\n",[15,785,786,787,790,791,794],{},"Запись ",[24,788,789],{},"flex: 1"," (эквивалент ",[24,792,793],{},"flex: 1 1 0",") — самый частый идиом: «пусть элементы поделят доступную ширину поровну». Комбинацией фиксированных и гибких элементов описывается большинство панельных раскладок: боковая колонка неизменной ширины и основная область, занимающая остальное.",[34,796,798],{"id":797},"типовые-паттерны","Типовые паттерны",[15,800,801],{},"Несколько задач раскладки встречаются так часто, что стали каноническими, и Flexbox решает их короче всего.",[15,803,804,807],{},[42,805,806],{},"Центрирование по обеим осям"," — задача, которая в старом CSS требовала ухищрений, а здесь занимает три строки:",[714,809,811],{"className":716,"code":810,"language":718,"meta":719,"style":719},".center {\n  display: flex;\n  justify-content: center;  \u002F* по главной оси *\u002F\n  align-items: center;      \u002F* по поперечной *\u002F\n}\n",[24,812,813,821,833,849,865],{"__ignoreMap":719},[60,814,815,818],{"class":724,"line":725},[60,816,817],{"class":728},".center",[60,819,820],{"class":732}," {\n",[60,822,823,826,828,830],{"class":724,"line":760},[60,824,825],{"class":736},"  display",[60,827,130],{"class":732},[60,829,206],{"class":736},[60,831,832],{"class":732},";\n",[60,834,836,839,841,843,846],{"class":724,"line":835},3,[60,837,838],{"class":736},"  justify-content",[60,840,130],{"class":732},[60,842,593],{"class":736},[60,844,845],{"class":732},";  ",[60,847,848],{"class":756},"\u002F* по главной оси *\u002F\n",[60,850,852,855,857,859,862],{"class":724,"line":851},4,[60,853,854],{"class":736},"  align-items",[60,856,130],{"class":732},[60,858,593],{"class":736},[60,860,861],{"class":732},";      ",[60,863,864],{"class":756},"\u002F* по поперечной *\u002F\n",[60,866,868],{"class":724,"line":867},5,[60,869,870],{"class":732},"}\n",[15,872,873,45,876,879],{},[42,874,875],{},"Прижатый к низу футер",[19,877,878],{},"sticky footer",") — подвал, который держится у нижнего края окна, даже когда контента мало, но уходит вниз за содержимым, когда его много. Решается вертикальным флекс-контейнером на всю высоту вьюпорта, у которого основная область растягивается:",[714,881,883],{"className":716,"code":882,"language":718,"meta":719,"style":719},"body {\n  min-height: 100dvh;\n  display: flex;\n  flex-direction: column;\n}\nmain { flex: 1; }  \u002F* забирает всё свободное место, выталкивая футер вниз *\u002F\n",[24,884,885,893,908,918,929,933],{"__ignoreMap":719},[60,886,887,891],{"class":724,"line":725},[60,888,890],{"class":889},"s9eBZ","body",[60,892,820],{"class":732},[60,894,895,898,900,903,906],{"class":724,"line":760},[60,896,897],{"class":736},"  min-height",[60,899,130],{"class":732},[60,901,902],{"class":736},"100",[60,904,905],{"class":749},"dvh",[60,907,832],{"class":732},[60,909,910,912,914,916],{"class":724,"line":835},[60,911,825],{"class":736},[60,913,130],{"class":732},[60,915,206],{"class":736},[60,917,832],{"class":732},[60,919,920,923,925,927],{"class":724,"line":851},[60,921,922],{"class":736},"  flex-direction",[60,924,130],{"class":732},[60,926,549],{"class":736},[60,928,832],{"class":732},[60,930,931],{"class":724,"line":867},[60,932,870],{"class":732},[60,934,936,939,941,943,945,947,949],{"class":724,"line":935},6,[60,937,938],{"class":889},"main",[60,940,733],{"class":732},[60,942,206],{"class":736},[60,944,130],{"class":732},[60,946,62],{"class":736},[60,948,753],{"class":732},[60,950,951],{"class":756},"\u002F* забирает всё свободное место, выталкивая футер вниз *\u002F\n",[15,953,954,45,957,960],{},[42,955,956],{},"Классическая трёхколоночная раскладка",[19,958,959],{},"holy grail",") — шапка, подвал и три колонки между ними (навигация, контент, боковая панель) — тоже собирается на Flexbox, хотя для неё, как и для любой двумерной задачи, естественнее подходит Grid, к которому мы сейчас и перейдём.",[29,962,964],{"id":963},"grid-двумерный-layout","Grid: двумерный layout",[34,966,968],{"id":967},"линии-треки-ячейки-зоны","Линии, треки, ячейки, зоны",[15,970,971,972,975,976,979,980,989],{},"Grid (",[19,973,974],{},"CSS Grid Layout",") — второй модуль раскладки, и его отличие от Flexbox принципиально: Grid работает сразу в ",[42,977,978],{},"двух измерениях",", управляя строками и колонками одновременно ",[51,981,983],{"className":982},[54],[56,984,986],{"href":985},"#ref-5",[60,987,988],{},"5",". Там, где Flexbox раскладывает поток элементов вдоль одной оси, Grid задаёт заранее спроектированную сетку, в ячейки которой элементы расставляются.",[15,991,992,993,45,996,999,1000,45,1003,1006,1007,1010,1011,45,1014,1017],{},"Терминология сетки опирается на четыре понятия. ",[42,994,995],{},"Линии",[19,997,998],{},"grid lines",") — горизонтальные и вертикальные разделители, нумеруемые с единицы (и с конца — отрицательными числами). ",[42,1001,1002],{},"Треки",[19,1004,1005],{},"tracks",") — полосы между соседними линиями, то есть колонки и строки. ",[42,1008,1009],{},"Ячейки"," — пересечения одной строки и одной колонки, наименьшая единица сетки. ",[42,1012,1013],{},"Зоны",[19,1015,1016],{},"areas",") — прямоугольные группы ячеек, которым можно дать имя и адресовать целиком.",[108,1019,110,1020,110,1024],{},[112,1021],{"src":1022,"alt":1023},"\u002Fimg\u002Faidt-mag-frontend\u002Ftopic-03\u002Fgrid_anatomy.svg","Анатомия Grid: нумерованные линии, треки-колонки и строки, ячейка, именованная зона, gap",[117,1025,1026],{},"Линии, треки, ячейки и зоны сетки Grid",[15,1028,1029,1030,1033],{},"Сетка объявляется на контейнере через ",[24,1031,1032],{},"display: grid"," и описание треков:",[714,1035,1037],{"className":716,"code":1036,"language":718,"meta":719,"style":719},".layout {\n  display: grid;\n  grid-template-columns: 240px 1fr;   \u002F* колонка 240px и колонка «остальное» *\u002F\n  grid-template-rows: auto 1fr auto;  \u002F* шапка по содержимому, тело, подвал *\u002F\n  gap: 16px;\n}\n",[24,1038,1039,1046,1056,1079,1100,1114],{"__ignoreMap":719},[60,1040,1041,1044],{"class":724,"line":725},[60,1042,1043],{"class":728},".layout",[60,1045,820],{"class":732},[60,1047,1048,1050,1052,1054],{"class":724,"line":760},[60,1049,825],{"class":736},[60,1051,130],{"class":732},[60,1053,210],{"class":736},[60,1055,832],{"class":732},[60,1057,1058,1061,1063,1066,1068,1070,1073,1076],{"class":724,"line":835},[60,1059,1060],{"class":736},"  grid-template-columns",[60,1062,130],{"class":732},[60,1064,1065],{"class":736},"240",[60,1067,750],{"class":749},[60,1069,774],{"class":736},[60,1071,1072],{"class":749},"fr",[60,1074,1075],{"class":732},";   ",[60,1077,1078],{"class":756},"\u002F* колонка 240px и колонка «остальное» *\u002F\n",[60,1080,1081,1084,1086,1089,1091,1093,1095,1097],{"class":724,"line":851},[60,1082,1083],{"class":736},"  grid-template-rows",[60,1085,130],{"class":732},[60,1087,1088],{"class":736},"auto",[60,1090,774],{"class":736},[60,1092,1072],{"class":749},[60,1094,777],{"class":736},[60,1096,845],{"class":732},[60,1098,1099],{"class":756},"\u002F* шапка по содержимому, тело, подвал *\u002F\n",[60,1101,1102,1105,1107,1110,1112],{"class":724,"line":867},[60,1103,1104],{"class":736},"  gap",[60,1106,130],{"class":732},[60,1108,1109],{"class":736},"16",[60,1111,750],{"class":749},[60,1113,832],{"class":732},[60,1115,1116],{"class":724,"line":935},[60,1117,870],{"class":732},[15,1119,1120,1121,1123,1124,1126,1127,1130,1131,1134,1135,1137,1138,1140],{},"Здесь появляется единица ",[24,1122,1072],{}," (fraction) — доля свободного места, аналог ",[24,1125,663],{}," для сетки. ",[24,1128,1129],{},"grid-template-columns: 1fr 2fr"," делит ширину в отношении 1 : 2; ",[24,1132,1133],{},"240px 1fr"," отдаёт первой колонке фиксированные 240 px, а второй — весь остаток. ",[24,1136,1072],{}," избавляет от ручного расчёта процентов и корректно учитывает ",[24,1139,572],{},".",[34,1142,1144,1145],{"id":1143},"явная-и-неявная-сетка-grid-template-areas","Явная и неявная сетка; ",[24,1146,1147],{},"grid-template-areas",[15,1149,1150,1151,207,1154,1157,1158,1161,1162,1165,1166,207,1169,1172,1173,1176],{},"Треки, заданные через ",[24,1152,1153],{},"grid-template-columns",[24,1155,1156],{},"grid-template-rows",", образуют ",[42,1159,1160],{},"явную"," сетку. Но элементов может оказаться больше, чем ячеек; тогда Grid достраивает ",[42,1163,1164],{},"неявные"," треки автоматически. Их размер задаётся свойствами ",[24,1167,1168],{},"grid-auto-rows",[24,1170,1171],{},"grid-auto-columns",", а направление, в котором сетка прирастает, — ",[24,1174,1175],{},"grid-auto-flow",". Так ведёт себя, например, лента карточек: колонок задано фиксированное число, а строки создаются по мере поступления карточек.",[15,1178,1179,1180,1183,1184,1187],{},"Размещать элементы по сетке можно двумя способами. Через номера линий — ",[24,1181,1182],{},"grid-column: 1 \u002F 3"," (от первой до третьей вертикальной линии, то есть на две колонки) — или, наглядно, через ",[42,1185,1186],{},"именованные зоны",". Второй способ превращает раскладку в почти графическую схему:",[714,1189,1191],{"className":716,"code":1190,"language":718,"meta":719,"style":719},".page {\n  display: grid;\n  grid-template-columns: 240px 1fr;\n  grid-template-areas:\n    \"header  header\"\n    \"sidebar main\"\n    \"footer  footer\";\n}\n.page > header  { grid-area: header; }\n.page > nav     { grid-area: sidebar; }\n.page > main    { grid-area: main; }\n.page > footer  { grid-area: footer; }\n",[24,1192,1193,1200,1210,1226,1234,1240,1245,1253,1258,1278,1296,1314],{"__ignoreMap":719},[60,1194,1195,1198],{"class":724,"line":725},[60,1196,1197],{"class":728},".page",[60,1199,820],{"class":732},[60,1201,1202,1204,1206,1208],{"class":724,"line":760},[60,1203,825],{"class":736},[60,1205,130],{"class":732},[60,1207,210],{"class":736},[60,1209,832],{"class":732},[60,1211,1212,1214,1216,1218,1220,1222,1224],{"class":724,"line":835},[60,1213,1060],{"class":736},[60,1215,130],{"class":732},[60,1217,1065],{"class":736},[60,1219,750],{"class":749},[60,1221,774],{"class":736},[60,1223,1072],{"class":749},[60,1225,832],{"class":732},[60,1227,1228,1231],{"class":724,"line":851},[60,1229,1230],{"class":736},"  grid-template-areas",[60,1232,1233],{"class":732},":\n",[60,1235,1236],{"class":724,"line":867},[60,1237,1239],{"class":1238},"sZZnC","    \"header  header\"\n",[60,1241,1242],{"class":724,"line":935},[60,1243,1244],{"class":1238},"    \"sidebar main\"\n",[60,1246,1248,1251],{"class":724,"line":1247},7,[60,1249,1250],{"class":1238},"    \"footer  footer\"",[60,1252,832],{"class":732},[60,1254,1256],{"class":724,"line":1255},8,[60,1257,870],{"class":732},[60,1259,1261,1263,1266,1269,1272,1275],{"class":724,"line":1260},9,[60,1262,1197],{"class":728},[60,1264,1265],{"class":749}," >",[60,1267,1268],{"class":889}," header",[60,1270,1271],{"class":732},"  { ",[60,1273,1274],{"class":736},"grid-area",[60,1276,1277],{"class":732},": header; }\n",[60,1279,1281,1283,1285,1288,1291,1293],{"class":724,"line":1280},10,[60,1282,1197],{"class":728},[60,1284,1265],{"class":749},[60,1286,1287],{"class":889}," nav",[60,1289,1290],{"class":732},"     { ",[60,1292,1274],{"class":736},[60,1294,1295],{"class":732},": sidebar; }\n",[60,1297,1299,1301,1303,1306,1309,1311],{"class":724,"line":1298},11,[60,1300,1197],{"class":728},[60,1302,1265],{"class":749},[60,1304,1305],{"class":889}," main",[60,1307,1308],{"class":732},"    { ",[60,1310,1274],{"class":736},[60,1312,1313],{"class":732},": main; }\n",[60,1315,1317,1319,1321,1324,1326,1328],{"class":724,"line":1316},12,[60,1318,1197],{"class":728},[60,1320,1265],{"class":749},[60,1322,1323],{"class":889}," footer",[60,1325,1271],{"class":732},[60,1327,1274],{"class":736},[60,1329,1330],{"class":732},": footer; }\n",[15,1332,1333,1334,1336],{},"Текстовая «картинка» в ",[24,1335,1147],{}," читается как план этажа: видно, что шапка и подвал тянутся на обе колонки, а середина разделена на боковую панель и основную область. Это одно из самых выразительных мест CSS — раскладка описывается декларативно и понятна с первого взгляда, а перестроить её под другой размер экрана можно, переписав одну эту «картинку» в медиа-запросе.",[34,1338,1340,1341,77,1344,77,1347],{"id":1339},"адаптивные-сетки-auto-fit-auto-fill-minmax","Адаптивные сетки: ",[24,1342,1343],{},"auto-fit",[24,1345,1346],{},"auto-fill",[24,1348,1349],{},"minmax",[15,1351,1352,1353,77,1356,1358,1359,1361,1362,1364],{},"Особую ценность Grid раскрывает в связке функций ",[24,1354,1355],{},"repeat",[24,1357,1349],{}," и ключевых слов ",[24,1360,1343],{}," \u002F ",[24,1363,1346],{},", дающих сетку, которая сама подстраивает число колонок под доступную ширину — без единого медиа-запроса:",[714,1366,1368],{"className":716,"code":1367,"language":718,"meta":719,"style":719},".cards {\n  display: grid;\n  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));\n  gap: 16px;\n}\n",[24,1369,1370,1377,1387,1419,1431],{"__ignoreMap":719},[60,1371,1372,1375],{"class":724,"line":725},[60,1373,1374],{"class":728},".cards",[60,1376,820],{"class":732},[60,1378,1379,1381,1383,1385],{"class":724,"line":760},[60,1380,825],{"class":736},[60,1382,130],{"class":732},[60,1384,210],{"class":736},[60,1386,832],{"class":732},[60,1388,1389,1391,1393,1395,1398,1400,1402,1404,1406,1408,1410,1412,1414,1416],{"class":724,"line":835},[60,1390,1060],{"class":736},[60,1392,130],{"class":732},[60,1394,1355],{"class":736},[60,1396,1397],{"class":732},"(",[60,1399,1343],{"class":736},[60,1401,77],{"class":732},[60,1403,1349],{"class":736},[60,1405,1397],{"class":732},[60,1407,1065],{"class":736},[60,1409,750],{"class":749},[60,1411,77],{"class":732},[60,1413,62],{"class":736},[60,1415,1072],{"class":749},[60,1417,1418],{"class":732},"));\n",[60,1420,1421,1423,1425,1427,1429],{"class":724,"line":851},[60,1422,1104],{"class":736},[60,1424,130],{"class":732},[60,1426,1109],{"class":736},[60,1428,750],{"class":749},[60,1430,832],{"class":732},[60,1432,1433],{"class":724,"line":867},[60,1434,870],{"class":732},[15,1436,1437,1438,207,1440,1442,1443,1445,1446,1448],{},"Читается это так: создавай столько колонок, сколько поместится, при условии что каждая не уже 240 px и не шире равной доли остатка. На широком экране карточки лягут в четыре-пять колонок, на планшете — в две, на телефоне — в одну, и всё это описано единственным правилом. Разница между ",[24,1439,1343],{},[24,1441,1346],{}," тонкая и проявляется, когда элементов меньше, чем помещается колонок: ",[24,1444,1343],{}," схлопывает пустые треки, растягивая имеющиеся карточки на всю ширину, а ",[24,1447,1346],{}," сохраняет пустые колонки, оставляя карточки исходного размера. Этот приём — «Repeat, Auto-fit, Minmax» — настолько распространён, что стал почти шаблоном для сеток карточек, плиток и галерей.",[34,1450,1452],{"id":1451},"критерии-выбора-между-grid-и-flexbox","Критерии выбора между Grid и Flexbox",[15,1454,1455],{},"Grid и Flexbox не конкуренты, а инструменты для разных задач, и выбор между ними сводится к одному вопросу: раскладка одномерна или двумерна.",[15,1457,1458,1459,1461,1462,1465],{},"Flexbox естествен, когда элементы выстраиваются вдоль ",[42,1460,517],{}," оси и их размер должен зависеть от содержимого: панель инструментов, ряд кнопок, список тегов, горизонтальное меню. Его логика — «от контента»: элементы сами занимают столько места, сколько им нужно, и делят остаток. Grid естествен, когда нужно управлять ",[42,1463,1464],{},"двумя"," измерениями сразу или задать жёсткую структуру, в которую контент вписывается: макет страницы целиком, сетка карточек с выравниванием по строкам и колонкам, сложные формы. Его логика — «от раскладки»: сначала проектируется сетка, затем в неё расставляется содержимое.",[15,1467,1468],{},"На практике оба модуля работают вместе: Grid задаёт крупную структуру страницы, а внутри отдельных её зон Flexbox раскладывает мелкие ряды элементов. Ошибка выбора обычно ощущается как борьба с инструментом — если приходится обходными путями добиваться выравнивания по второй оси во Flexbox, это сигнал, что задача на самом деле двумерная и просит Grid.",[29,1470,1472],{"id":1471},"адаптивная-вёрстка","Адаптивная вёрстка",[34,1474,1476],{"id":1475},"подход-mobile-first","Подход mobile-first",[15,1478,1479,1480,1483,1484,1487],{},"Одна и та же страница должна быть удобной и на телефоне шириной 360 px, и на мониторе шириной 1920 px. Подход, ставший стандартом, — ",[42,1481,1482],{},"mobile-first",": базовые стили пишутся для узкого экрана, а стили для широких добавляются поверх, по мере роста доступного места. Причина не только в растущей доле мобильного трафика. Раскладка для узкого экрана обычно проще — один столбец, вертикальный поток, — и надстраивать над простой основой усложнения удобнее, чем упрощать сложное. Технически mobile-first выражается в том, что дополнительные правила навешиваются медиа-запросами с условием ",[24,1485,1486],{},"min-width",": «начиная с такой-то ширины — применить». Это согласуется с идеей прогрессивного улучшения: сначала работоспособная база, затем обогащение возможностями там, где для них есть место.",[34,1489,1491],{"id":1490},"медиа-запросы-и-брейкпоинты","Медиа-запросы и брейкпоинты",[15,1493,1494,1495,1498,1499,1502,1503,1512],{},"Медиа-запрос (англ. ",[19,1496,1497],{},"media query",") — условие, при котором применяется группа правил; в теме 2, вводя ",[24,1500,1501],{},"prefers-color-scheme",", мы обещали разобрать этот механизм здесь ",[51,1504,1506],{"className":1505},[54],[56,1507,1509],{"href":1508},"#ref-6",[60,1510,1511],{},"6",". Для адаптивной раскладки главная медиа-фича — ширина вьюпорта:",[714,1514,1516],{"className":716,"code":1515,"language":718,"meta":719,"style":719},"\u002F* база: один столбец, mobile-first *\u002F\n.grid { display: grid; grid-template-columns: 1fr; gap: 16px; }\n\n\u002F* с 768px — две колонки *\u002F\n@media (min-width: 768px) {\n  .grid { grid-template-columns: repeat(2, 1fr); }\n}\n\n\u002F* с 1200px — четыре *\u002F\n@media (min-width: 1200px) {\n  .grid { grid-template-columns: repeat(4, 1fr); }\n}\n",[24,1517,1518,1523,1560,1566,1571,1590,1616,1620,1624,1629,1646,1670],{"__ignoreMap":719},[60,1519,1520],{"class":724,"line":725},[60,1521,1522],{"class":756},"\u002F* база: один столбец, mobile-first *\u002F\n",[60,1524,1525,1528,1530,1532,1534,1536,1539,1541,1543,1545,1547,1549,1551,1553,1555,1557],{"class":724,"line":760},[60,1526,1527],{"class":728},".grid",[60,1529,733],{"class":732},[60,1531,129],{"class":736},[60,1533,130],{"class":732},[60,1535,210],{"class":736},[60,1537,1538],{"class":732},"; ",[60,1540,1153],{"class":736},[60,1542,130],{"class":732},[60,1544,62],{"class":736},[60,1546,1072],{"class":749},[60,1548,1538],{"class":732},[60,1550,572],{"class":736},[60,1552,130],{"class":732},[60,1554,1109],{"class":736},[60,1556,750],{"class":749},[60,1558,1559],{"class":732},"; }\n",[60,1561,1562],{"class":724,"line":835},[60,1563,1565],{"emptyLinePlaceholder":1564},true,"\n",[60,1567,1568],{"class":724,"line":851},[60,1569,1570],{"class":756},"\u002F* с 768px — две колонки *\u002F\n",[60,1572,1573,1576,1578,1580,1582,1585,1587],{"class":724,"line":867},[60,1574,1575],{"class":749},"@media",[60,1577,73],{"class":732},[60,1579,1486],{"class":736},[60,1581,130],{"class":732},[60,1583,1584],{"class":736},"768",[60,1586,750],{"class":749},[60,1588,1589],{"class":732},") {\n",[60,1591,1592,1595,1597,1599,1601,1603,1605,1607,1609,1611,1613],{"class":724,"line":935},[60,1593,1594],{"class":728},"  .grid",[60,1596,733],{"class":732},[60,1598,1153],{"class":736},[60,1600,130],{"class":732},[60,1602,1355],{"class":736},[60,1604,1397],{"class":732},[60,1606,157],{"class":736},[60,1608,77],{"class":732},[60,1610,62],{"class":736},[60,1612,1072],{"class":749},[60,1614,1615],{"class":732},"); }\n",[60,1617,1618],{"class":724,"line":1247},[60,1619,870],{"class":732},[60,1621,1622],{"class":724,"line":1255},[60,1623,1565],{"emptyLinePlaceholder":1564},[60,1625,1626],{"class":724,"line":1260},[60,1627,1628],{"class":756},"\u002F* с 1200px — четыре *\u002F\n",[60,1630,1631,1633,1635,1637,1639,1642,1644],{"class":724,"line":1280},[60,1632,1575],{"class":749},[60,1634,73],{"class":732},[60,1636,1486],{"class":736},[60,1638,130],{"class":732},[60,1640,1641],{"class":736},"1200",[60,1643,750],{"class":749},[60,1645,1589],{"class":732},[60,1647,1648,1650,1652,1654,1656,1658,1660,1662,1664,1666,1668],{"class":724,"line":1298},[60,1649,1594],{"class":728},[60,1651,733],{"class":732},[60,1653,1153],{"class":736},[60,1655,130],{"class":732},[60,1657,1355],{"class":736},[60,1659,1397],{"class":732},[60,1661,513],{"class":736},[60,1663,77],{"class":732},[60,1665,62],{"class":736},[60,1667,1072],{"class":749},[60,1669,1615],{"class":732},[60,1671,1672],{"class":724,"line":1316},[60,1673,870],{"class":732},[15,1675,1676,1677,45,1680,1683],{},"Ширина, при которой раскладка меняется, называется ",[42,1678,1679],{},"точкой разрыва",[19,1681,1682],{},"breakpoint","). Распространённая ошибка — привязывать брейкпоинты к диагоналям популярных устройств: модельный ряд меняется, а «айфонные» 375 px устаревают. Правильнее выбирать точки разрыва по содержимому: там, где раскладка начинает выглядеть плохо — строки становятся слишком длинными, карточки чрезмерно широкими, — там и ставить брейкпоинт, независимо от того, какому устройству эта ширина соответствует.",[34,1685,1687],{"id":1686},"container-queries-как-альтернатива-медиа-запросам","Container Queries как альтернатива медиа-запросам",[15,1689,1690,1691,1694],{},"У медиа-запросов есть принципиальное ограничение: они реагируют на размер ",[42,1692,1693],{},"вьюпорта",", а не на размер места, отведённого конкретному компоненту. Одна и та же карточка может стоять и в узкой боковой колонке, и в широкой основной области; вьюпорт при этом один, а вот пространства у карточки в двух местах разное — и медиа-запрос эту разницу не различает. Компонент оказывается вынужден «знать» о глобальной ширине окна, хотя логично ему было бы реагировать на собственный контейнер.",[15,1696,1697,1698,45,1701,1704,1705,1714,1715,1718],{},"Эту брешь закрывают ",[42,1699,1700],{},"контейнерные запросы",[19,1702,1703],{},"container queries",") — относительно недавнее дополнение CSS ",[51,1706,1708],{"className":1707},[54],[56,1709,1711],{"href":1710},"#ref-7",[60,1712,1713],{},"7",". Родительский элемент объявляется контейнером, а его потомки получают возможность реагировать на ",[19,1716,1717],{},"его"," размер:",[714,1720,1722],{"className":716,"code":1721,"language":718,"meta":719,"style":719},".card-host { container-type: inline-size; }\n\n@container (min-width: 400px) {\n  .card { grid-template-columns: auto 1fr; }  \u002F* картинка слева от текста *\u002F\n}\n",[24,1723,1724,1737,1741,1749,1771],{"__ignoreMap":719},[60,1725,1726,1729,1731,1734],{"class":724,"line":725},[60,1727,1728],{"class":728},".card-host",[60,1730,733],{"class":732},[60,1732,1733],{"class":736},"container-type",[60,1735,1736],{"class":732},": inline-size; }\n",[60,1738,1739],{"class":724,"line":760},[60,1740,1565],{"emptyLinePlaceholder":1564},[60,1742,1743,1746],{"class":724,"line":835},[60,1744,1745],{"class":749},"@container",[60,1747,1748],{"class":732}," (min-width: 400px) {\n",[60,1750,1751,1754,1756,1758,1760,1762,1764,1766,1768],{"class":724,"line":851},[60,1752,1753],{"class":728},"  .card",[60,1755,733],{"class":732},[60,1757,1153],{"class":736},[60,1759,130],{"class":732},[60,1761,1088],{"class":736},[60,1763,774],{"class":736},[60,1765,1072],{"class":749},[60,1767,753],{"class":732},[60,1769,1770],{"class":756},"\u002F* картинка слева от текста *\u002F\n",[60,1772,1773],{"class":724,"line":867},[60,1774,870],{"class":732},[15,1776,1777],{},"Теперь карточка перестраивается сама, исходя из ширины отведённого ей места, где бы её ни разместили. Это сдвиг от «страница знает про все свои компоненты» к «компонент самодостаточен и заботится о себе» — то, что давно ожидалось от по-настоящему модульного, переиспользуемого интерфейса. Медиа-запросы не отменяются: они по-прежнему уместны для решений уровня всей страницы (общий каркас, поля, глобальная типографика), тогда как контейнерные запросы — для адаптации отдельных компонентов.",[34,1779,1781],{"id":1780},"гибкий-layout-без-точек-разрыва","Гибкий layout без точек разрыва",[15,1783,1784,1785,45,1788,1791,1792,1801,1802,207,1805,1808,1809,1812,1813,1816,1817,1820],{},"Крайняя точка развития адаптивности — раскладка, которая почти не нуждается в явных брейкпоинтах, а плавно подстраивается сама. Такой подход называют ",[42,1786,1787],{},"интринсивным дизайном",[19,1789,1790],{},"intrinsic web design",", термин Джен Симмонс) ",[51,1793,1795],{"className":1794},[54],[56,1796,1798],{"href":1797},"#ref-8",[60,1799,1800],{},"8",". Он опирается на уже знакомые нам средства: ",[24,1803,1804],{},"clamp",[24,1806,1807],{},"min","\u002F",[24,1810,1811],{},"max"," из темы 2 для «жидких» размеров, сетки на ",[24,1814,1815],{},"repeat(auto-fit, minmax(...))",", свойство ",[24,1818,1819],{},"flex-wrap"," для рядов, переносящихся по мере нехватки места. Вместо ступенчатого переключения между фиксированными макетами на заданных ширинах раскладка непрерывно течёт, занимая ровно столько места, сколько есть.",[15,1822,1823,1824,1827],{},"Дисциплина здесь в том, чтобы поручать вычисление размеров самому CSS, а не перечислять вручную случаи для каждого диапазона. Правило ",[24,1825,1826],{},"grid-template-columns: repeat(auto-fit, minmax(240px, 1fr))"," заменяет три медиа-запроса из примера выше — и делает это устойчивее, потому что не привязано ни к каким конкретным порогам. На практике интринсивный подход и брейкпоинты сочетают: мелкую адаптацию отдают гибким единицам и авторастущим сеткам, а явные точки разрыва оставляют для немногих случаев, где раскладка должна перестроиться качественно, а не просто сжаться.",[29,1829,1831],{"id":1830},"итоги-темы","Итоги темы",[15,1833,1834,1835,1837,1838,1840,1841,1843],{},"Раскладка в CSS — это несколько слоёв механизмов, надстроенных друг над другом. В основании лежит нормальный поток: блочные элементы идут сверху вниз, строчные — слева направо, и большая часть контента раскладывается им без вмешательства. Позиционирование через ",[24,1836,300],{}," выводит отдельные элементы из потока и привязывает их к предку, вьюпорту или порогу прокрутки; вместе с ним приходит контекст наложения, объясняющий, почему ",[24,1839,413],{}," работает не так прямолинейно, как кажется. Устаревший ",[24,1842,26],{}," из инструмента раскладки вернулся к своей единственной честной роли — обтеканию врезки текстом.",[15,1845,1846],{},"Основную работу по раскладке сегодня делят два специализированных модуля. Flexbox распределяет элементы вдоль одной оси и хорош, когда размер идёт от содержимого; Grid проектирует двумерную сетку, в которую вписывается контент. Выбор между ними — вопрос размерности задачи, а не вкуса, и на практике они работают в связке: Grid держит каркас страницы, Flexbox — ряды внутри него. Адаптивность выстраивается поверх всего этого: mobile-first как отправная точка, медиа-запросы для решений уровня страницы, контейнерные запросы для самодостаточных компонентов и гибкие единицы для раскладки, которая подстраивается сама, обходясь без лишних точек разрыва. Освоив эти механизмы, можно собрать интерфейс, одинаково пригодный от телефона до широкого монитора, — что и станет задачей практического занятия 3.",[29,1848,1850],{"id":1849},"литература","Литература",[1852,1853,1856,1861,1865,1869,1873,1877,1881,1885],"ol",{"className":1854},[1855],"references",[1857,1858,1860],"li",{"id":1859},"ref-1","Consortium} {. W. W. Cascading Style Sheets Level 2 Revision 1 (CSS 2.1) Specification. — 2011, https:\u002F\u002Fwww.w3.org\u002FTR\u002FCSS21\u002F.",[1857,1862,1864],{"id":1863},"ref-2","Consortium} {. W. W. CSS Display Module Level 3. — 2023, https:\u002F\u002Fwww.w3.org\u002FTR\u002Fcss-display-3\u002F.",[1857,1866,1868],{"id":1867},"ref-3","Consortium} {. W. W. CSS Positioned Layout Module Level 3. — 2023, https:\u002F\u002Fwww.w3.org\u002FTR\u002Fcss-position-3\u002F.",[1857,1870,1872],{"id":1871},"ref-4","Consortium} {. W. W. CSS Flexible Box Layout Module Level 1. — 2018, https:\u002F\u002Fwww.w3.org\u002FTR\u002Fcss-flexbox-1\u002F.",[1857,1874,1876],{"id":1875},"ref-5","Consortium} {. W. W. CSS Grid Layout Module Level 2. — 2023, https:\u002F\u002Fwww.w3.org\u002FTR\u002Fcss-grid-2\u002F.",[1857,1878,1880],{"id":1879},"ref-6","Consortium} {. W. W. Media Queries Level 5. — 2024, https:\u002F\u002Fwww.w3.org\u002FTR\u002Fmediaqueries-5\u002F.",[1857,1882,1884],{"id":1883},"ref-7","Consortium} {. W. W. CSS Containment Module Level 3. — 2024, https:\u002F\u002Fwww.w3.org\u002FTR\u002Fcss-contain-3\u002F.",[1857,1886,1888],{"id":1887},"ref-8","Bell A., Pickering H. Every Layout: Relearn CSS Layout. — 2023, https:\u002F\u002Fevery-layout.dev\u002F.",[1890,1891,1892],"style",{},"html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}",{"title":719,"searchDepth":760,"depth":760,"links":1894},[1895,1901,1909,1917,1925,1931,1932],{"id":31,"depth":760,"text":32,"children":1896},[1897,1898,1900],{"id":36,"depth":835,"text":37},{"id":125,"depth":835,"text":1899},"Свойство display: block, inline, inline-block, none",{"id":225,"depth":835,"text":226},{"id":293,"depth":760,"text":294,"children":1902},[1903,1905,1907],{"id":297,"depth":835,"text":1904},"position: static, relative, absolute, fixed, sticky",{"id":409,"depth":835,"text":1906},"Контекст наложения и z-index",{"id":465,"depth":835,"text":1908},"float как устаревающий механизм",{"id":492,"depth":760,"text":493,"children":1910},[1911,1912,1914,1916],{"id":496,"depth":835,"text":497},{"id":562,"depth":835,"text":1913},"Свойства распределения: justify-content, align-items, gap",{"id":660,"depth":835,"text":1915},"flex-grow, flex-shrink, flex-basis: реакция на переполнение",{"id":797,"depth":835,"text":798},{"id":963,"depth":760,"text":964,"children":1918},[1919,1920,1922,1924],{"id":967,"depth":835,"text":968},{"id":1143,"depth":835,"text":1921},"Явная и неявная сетка; grid-template-areas",{"id":1339,"depth":835,"text":1923},"Адаптивные сетки: auto-fit, auto-fill, minmax",{"id":1451,"depth":835,"text":1452},{"id":1471,"depth":760,"text":1472,"children":1926},[1927,1928,1929,1930],{"id":1475,"depth":835,"text":1476},{"id":1490,"depth":835,"text":1491},{"id":1686,"depth":835,"text":1687},{"id":1780,"depth":835,"text":1781},{"id":1830,"depth":760,"text":1831},{"id":1849,"depth":760,"text":1850},"aidt-mag-frontend","В теме 1 мы описали структуру документа, в теме 2 — оформление отдельных элементов: цвет, шрифт, размеры коробки. Но интерфейс — это не набор независимо оформленных блоков, а их взаимное расположение на плоскости: колонки рядом, шапка сверху, карточки сеткой, боковая панель, прижатая к краю. За это отвечает раскладка (англ. layout) — совокупность механизмов CSS, определяющих, где именно окажется каждый элемент. Раскладка — та часть CSS, которая исторически менялась сильнее всего: от табличной вёрстки девяностых через float к специально спроектированным Flexbox и Grid. Мы разберём её послойно — от потока документа, работающего по умолчанию, к позиционированию, затем к двум современным модулям раскладки, и завершим адаптивностью: тем, как одна вёрстка обслуживает экраны от телефона до широкого монитора.",null,"md",false,{},"\u002Fcourses\u002Faidt-mag-frontend\u002Ftopic-03-content","content",{"title":6,"description":1934},"courses\u002Faidt-mag-frontend\u002Ftopic-03-content","topic-03","LP7i9PMU5EPDncikISdyit5dLvCVhkRmF6EKEW-I9Wg",{"id":1946,"title":1947,"body":1948,"course_slug":1933,"description":719,"env_label":1935,"env_url":1935,"extension":1936,"group":1935,"is_course_project":1937,"is_index":1937,"level":1935,"meta":2171,"navigation":1564,"path":2172,"section":2173,"seo":2174,"stem":2175,"topic_number":835,"topic_slug":1943,"__hash__":2176},"courses\u002Fcourses\u002Faidt-mag-frontend\u002Ftopic-03-additional.md","Дополнительные материалы. Тема 3. Layout: позиционирование, Flexbox, Grid, адаптивность",{"type":8,"value":1949,"toc":2164},[1950,1953,1955,2007,2009,2044,2046,2064,2066,2100,2102],[11,1951,1947],{"id":1952},"дополнительные-материалы-тема-3-layout-позиционирование-flexbox-grid-адаптивность",[29,1954,32],{"id":31},[1956,1957,1958,1967,1975,1990],"ul",{},[1857,1959,1960,1966],{},[56,1961,1965],{"href":1962,"rel":1963},"https:\u002F\u002Fdeveloper.mozilla.org\u002Fru\u002Fdocs\u002FWeb\u002FCSS\u002FGuides\u002FDisplay\u002FFlow_layout",[1964],"nofollow","MDN: поточная раскладка CSS"," — определение нормального потока и различий между блочными и строчными элементами, со ссылками на смежные темы: контексты форматирования, взаимодействие потока с переполнением и режимами письма.",[1857,1968,1969,1974],{},[56,1970,1973],{"href":1971,"rel":1972},"https:\u002F\u002Fdeveloper.mozilla.org\u002Fru\u002Fdocs\u002FWeb\u002FCSS\u002FCSS_flow_layout\u002FIntroduction_to_formatting_contexts",[1964],"MDN: введение в контексты форматирования"," — обзор всех типов контекстов форматирования (блочного, строчного, флекс- и грид-контекста) и условий, при которых каждый из них возникает.",[1857,1976,1977,1982,1983,77,1985,77,1987,1989],{},[56,1978,1981],{"href":1979,"rel":1980},"https:\u002F\u002Fdeveloper.mozilla.org\u002Fru\u002Fdocs\u002FWeb\u002FCSS\u002FCSS_display\u002FBlock_formatting_context",[1964],"MDN: блочный контекст форматирования"," — способы создания BFC (",[24,1984,26],{},[24,1986,276],{},[24,1988,283],{}," и др.) и то, как новый контекст решает две конкретные задачи: содержит внутри себя плавающие элементы и отменяет схлопывание margin с соседями.",[1857,1991,1992,1997,1998,77,2000,77,2002,207,2004,2006],{},[56,1993,1996],{"href":1994,"rel":1995},"https:\u002F\u002Fhtmlacademy.ru\u002Fblog\u002Fcss\u002Fdisplay",[1964],"HTML Academy: свойство display"," — разбор значений ",[24,1999,133],{},[24,2001,136],{},[24,2003,139],{},[24,2005,142],{}," на примерах кода и скриншотах.",[29,2008,294],{"id":293},[1956,2010,2011,2022,2033],{},[1857,2012,2013,2018,2019,2021],{},[56,2014,2017],{"href":2015,"rel":2016},"https:\u002F\u002Fhtmlacademy.ru\u002Fblog\u002Fcss\u002Fposition",[1964],"HTML Academy: CSS position"," — разбор всех пяти значений ",[24,2020,300],{}," с примерами кода, скриншотами и отдельным разделом про z-index и доступность.",[1857,2023,2024,2029,2030,2032],{},[56,2025,2028],{"href":2026,"rel":2027},"https:\u002F\u002Fdeveloper.mozilla.org\u002Fru\u002Fdocs\u002FLearn_web_development\u002FCore\u002FCSS_layout\u002FPositioning",[1964],"MDN Learn Web Development: позиционирование"," — учебный модуль с пошаговыми примерами для каждого значения ",[24,2031,300],{},", живыми демонстрациями в отдельных файлах и тестами для самопроверки в конце.",[1857,2034,2035,2040,2041,2043],{},[56,2036,2039],{"href":2037,"rel":2038},"https:\u002F\u002Fblog.sf.education\u002Fkak-rabotaet-css-position\u002F",[1964],"SF Education: как работает CSS position"," — текстовое объяснение назначения и контекста применения каждого значения ",[24,2042,300],{}," без примеров кода.",[29,2045,493],{"id":492},[1956,2047,2048,2056],{},[1857,2049,2050,2055],{},[56,2051,2054],{"href":2052,"rel":2053},"https:\u002F\u002Fflexboxfroggy.com\u002F#ru",[1964],"Flexbox Froggy"," — браузерная игра-тренажёр: свойства флекс-контейнера отрабатываются на серии уровней, где нужно расставить лягушек по кувшинкам.",[1857,2057,2058,2063],{},[56,2059,2062],{"href":2060,"rel":2061},"https:\u002F\u002Fdoka.guide\u002Fcss\u002Fflexbox-guide\u002F",[1964],"Дока: гайд по Flexbox"," — руководство по всем свойствам флекс-контейнера и флекс-элементов с интерактивными демо для каждого свойства и разделом вопросов для собеседований.",[29,2065,964],{"id":963},[1956,2067,2068,2076,2084,2092],{},[1857,2069,2070,2075],{},[56,2071,2074],{"href":2072,"rel":2073},"https:\u002F\u002Fcssgridgarden.com\u002F#ru",[1964],"CSS Grid Garden"," — браузерная игра-тренажёр на свойства Grid: нужно поливать грядки с морковью, управляя сеткой через код.",[1857,2077,2078,2083],{},[56,2079,2082],{"href":2080,"rel":2081},"https:\u002F\u002Fgridbyexample.com",[1964],"Grid by Example"," — сайт Рейчел Эндрю с короткими видео и интерактивными примерами по функциям спецификации Grid, а также готовыми шаблонами для типовых задач раскладки; на английском языке.",[1857,2085,2086,2091],{},[56,2087,2090],{"href":2088,"rel":2089},"https:\u002F\u002Fdoka.guide\u002Fcss\u002Fgrid-guide\u002F",[1964],"Дока: гайд по Grid"," — руководство по свойствам грид-контейнера и элементов с демо и наглядными диаграммами линий, ячеек и треков.",[1857,2093,2094,2099],{},[56,2095,2098],{"href":2096,"rel":2097},"https:\u002F\u002Fhabr.com\u002Fru\u002Fcompanies\u002Ftimeweb\u002Farticles\u002F1004986\u002F",[1964],"Flex vs Grid: объяснение разницы на практике (блог Timeweb)"," — сравнение на четырёх сценариях («карточки в ряд», «кнопка внизу карточки», «облако тегов», «макет страницы»), какой из двух модулей раскладки решает задачу естественнее.",[29,2101,1472],{"id":1471},[1956,2103,2104,2112,2139,2156],{},[1857,2105,2106,2111],{},[56,2107,2110],{"href":2108,"rel":2109},"https:\u002F\u002Fdeveloper.mozilla.org\u002Fru\u002Fdocs\u002FLearn_web_development\u002FCore\u002FCSS_layout\u002FResponsive_Design",[1964],"MDN Learn Web Development: отзывчивый дизайн"," — учебный модуль о происхождении подхода, mobile-first, медиавыражениях и роли Flexbox, Grid и Multicol как изначально отзывчивых инструментов раскладки; отдельно разбирает адаптацию изображений, типографики и метатег viewport.",[1857,2113,2114,2119,2120,2122,2123,77,2125,2128,2129,77,2132,77,2135,2138],{},[56,2115,2118],{"href":2116,"rel":2117},"https:\u002F\u002Fdeveloper.mozilla.org\u002Fru\u002Fdocs\u002FWeb\u002FCSS\u002FGuides\u002FMedia_queries\u002FUsing",[1964],"MDN: использование медиавыражений"," — справочник по синтаксису ",[24,2121,1575],{},": типы устройств, медиа-фичи (",[24,2124,1486],{},[24,2126,2127],{},"hover"," и др.), логические операторы ",[24,2130,2131],{},"and",[24,2133,2134],{},"not",[24,2136,2137],{},"only"," и запись через запятую.",[1857,2140,2141,2146,2147,77,2149,77,2152,2155],{},[56,2142,2145],{"href":2143,"rel":2144},"https:\u002F\u002Ffruntend.com\u002Fposts\u002Fpolnoe-rukovodstvo-po-container-queries-v-css",[1964],"fruntend: полное руководство по Container Queries в CSS"," — синтаксис и свойства ",[24,2148,1733],{},[24,2150,2151],{},"container-name",[24,2153,2154],{},"container"," на примере одной и той же карточки в широком и узком контейнере, сравнение с медиа-запросами, таблица поддержки браузерами.",[1857,2157,2158,2163],{},[56,2159,2162],{"href":2160,"rel":2161},"https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=jBwBACbRuGY",[1964],"Jen Simmons: Everything You Know About Web Design Just Changed (An Event Apart, YouTube)"," — запись доклада 2018 года, в котором введён термин «интринсивный дизайн»: разбор перехода от вёрстки, собираемой обходными приёмами, к раскладке, описываемой напрямую средствами Grid и Flexbox.",{"title":719,"searchDepth":760,"depth":760,"links":2165},[2166,2167,2168,2169,2170],{"id":31,"depth":760,"text":32},{"id":293,"depth":760,"text":294},{"id":492,"depth":760,"text":493},{"id":963,"depth":760,"text":964},{"id":1471,"depth":760,"text":1472},{},"\u002Fcourses\u002Faidt-mag-frontend\u002Ftopic-03-additional","additional",{"title":1947,"description":719},"courses\u002Faidt-mag-frontend\u002Ftopic-03-additional","rA1sN4rCCvcgw6uLds5ryUl78rruGiZ4jEAOkhEWNYc",{"id":2178,"title":2179,"body":2180,"course_slug":1933,"description":2232,"env_label":1935,"env_url":1935,"extension":1936,"group":2233,"is_course_project":1937,"is_index":1564,"level":2234,"meta":2235,"navigation":1564,"path":2254,"section":1935,"seo":2255,"stem":2256,"topic_number":1935,"topic_slug":1935,"__hash__":2257},"courses\u002Fcourses\u002Faidt-mag-frontend\u002Findex.md","Разработка пользовательских веб-интерфейсов",{"type":8,"value":2181,"toc":2230},[2182,2189,2196,2203,2206,2223],[15,2183,2184,2185,1140],{},"Требования к содержанию и оформлению материалов — в ",[56,2186,2188],{"href":2187},".\u002Fshared\u002FSTYLEGUIDE","shared\u002FSTYLEGUIDE.md",[15,2190,2191,2192,1140],{},"Содержание курса — в ",[56,2193,2195],{"href":2194},".\u002Ftopics","topics.md",[15,2197,2198,2199,1140],{},"Порядок сдачи практических занятий и работа с git — в ",[56,2200,2202],{"href":2201},".\u002Fshared\u002Fsubmission","shared\u002Fsubmission.md",[15,2204,2205],{},"Издательские метаданные:",[1956,2207,2208,2216],{},[1857,2209,2210,2211,2215],{},"учебного пособия (по теории) — в ",[56,2212,2214],{"href":2213},".\u002Fpublishing\u002Ftextbook.yaml","publishing\u002Ftextbook.yaml",";",[1857,2217,2218,2219,1140],{},"практикума (по заданиям) — в ",[56,2220,2222],{"href":2221},".\u002Fpublishing\u002Fpracticum.yaml","publishing\u002Fpracticum.yaml",[15,2224,2225,2226,1140],{},"Общие части практикума (пояснительная записка и правила выполнения работ) — в ",[56,2227,2229],{"href":2228},".\u002Fpracticum\u002F","practicum\u002F",{"title":719,"searchDepth":760,"depth":760,"links":2231},[],"Требования к содержанию и оформлению материалов — в shared\u002FSTYLEGUIDE.md.","magistracy","магистратура",{"topics_count":1280,"has_lr":1937,"has_pz":1564,"has_course_project":1937,"final_assessment":2236,"tech_focus":2237,"kind":2238,"authors":2239,"publication":2246},"дифф. зачёт","TypeScript + Vite, без фреймворков","Учебное пособие",[2240],{"last_name":2241,"first_name":2242,"patronymic":2243,"role":2244,"affiliation":2245,"email":1935},"Рындин","Никита","Александрович","автор","ВГТУ",{"city":2247,"year":2248,"founder":2249,"publisher":2250,"udk":719,"bbk":719,"shelf_mark":719,"isbn":719,"approval_body":2253},"Воронеж",2026,"Министерство науки и высшего образования Российской Федерации",{"short":2245,"full":2251,"address":2252},"Федеральное государственное бюджетное образовательное учреждение высшего образования «Воронежский государственный технический университет»\n","394026, Воронеж, Московский проспект, 14","Издается по решению редакционно-издательского совета\nВоронежского государственного технического университета\n","\u002Fcourses\u002Faidt-mag-frontend",{"title":2179,"description":2232},"courses\u002Faidt-mag-frontend\u002Findex","iMYEd7hNEHxF61y1SzYGvxfRDscqJIg-IxlFsYdmxUw",1791350714314]