Овладяването на уеб оформлението без овладяване на CSS е почти толкова осъществимо, колкото да се научите да плувате на суха земя. Но за разлика от плуването - което, след като бъде усвоено, е умение, което остава с вас за цял живот - овладяването на CSS е процес, който всъщност никога не завършва, тъй като самият CSS непрекъснато се развива.
Предизвикателството се задълбочава от разликите в внедряването и поддръжката на CSS в различните браузъри (и дори в различните версии на един и същ браузър), както и различните нива на приемане на препоръки за CSS. Вече повече от десетилетие уеб дизайнерите и разработчиците се борят със спорадични и непоследователни изблици на допълнителни Поддържат се CSS3 функции във всяка нова версия на браузъра.
Но както и да е, овладяване на CSS е абсолютна необходимост за всяко твърдо вещество уеб дизайнер или разработчик . Тази статия ще ви преведе през някои основни принципи на оформлението на CSS, от класически техники на CSS2 до най-новите подходи за оформление в CSS3.
ЗАБЕЛЕЖКА: Всички примерни кодове в тази статия използват HTML5 елементи и Sass синтаксис. Пълният работен код може да бъде клониран от https://github.com/laureanoarcanio/css-layout-examples .
Един от най-добрите начини да научите технология е да имате конкретен случай на употреба, който се опитвате да поддържате, или определен проблем, който се опитвате да разрешите. За тази цел ще се съсредоточим върху случай на употреба със специфичен набор от изисквания.
Нашият случай на употреба се състои от оформление на уеб приложение с известно динамично поведение. Той ще има фиксирани елементи на страницата като горен колонтитул, долен колонтитул, меню за навигация и под-навигация, както и разгъващо се съдържание. Ето конкретните изисквания за оформление:
За начало, ето HTML5 маркирането, което ще използваме с нашата примерна реализация, използвайки класически CSS:
z-index
В CSS2 можем да постигнем фиксираните елементи на страницата (горен колонтитул и т.н.), като използваме позициониран модел на оформление, който използва фиксирано позициониране.
Освен това ще използваме z-index
CSS свойство да гарантира, че нашите фиксирани елементи остават „отгоре“ на останалото съдържание на страницата. z-index
свойството определя реда на стека на елемент, където елемент с по-голям ред на стека винаги е „отгоре“ на елемент с по-нисък ред на стека. Имайте предвид, че z-index
имотът работи само с позициониран елементи. За нашия пример ще използваме произволно width
стойност 20 (което е по-високо от подразбирането), за да гарантираме, че нашите фиксирани елементи остават визуално на преден план.
Също така ще зададем #header, #footer { position: fixed; width: 100%; z-index: 20; } #header { top: 0; height: 5em; } #footer { bottom: 0; height: 3em; }
свойство до 100%, което инструктира браузъра да използва цялото налично пространство хоризонтално за елемента.
#nav
Добре, това са горният и долният колонтитул. Но какво ще кажете за #subnav
и #nav
?
За #subnav
и top
, ще използваме малко по-сложна техника, известна като Разширение на CSS , който може да се използва при позициониране на елементи като фиксиран (т.е. на фиксирана позиция на страницата) или като абсолютно (т.е. на определена позиция спрямо най-близката позициониран предшественик или към съдържащия блок).
Вертикалното разширяване се постига чрез задаване на двете bottom
и left
свойства на елемент до фиксирана стойност, така че елементът ще се разшири вертикално, за да използва съответно останалото вертикално пространство. По принцип това, което правите, е да обвържете горната част на елемента на определено разстояние от горната част на страницата и долната част на елемента до определено разстояние от долната част на страницата, така че елементът се разширява, за да запълни цялото вертикално пространство между тези две точки.
По подобен начин се постига хоризонтално разширение чрез задаване на двете right
и #nav, #subnav { position: fixed; top: 6em; /* leave 1em margin below header */ bottom: 4em; /* leave 1em margin above footer */ z-index: 20; } #nav { left: 0; width: 5em; } #subnav { left: 6em; /* leave 1em margin to right of nav */ width: 13em; }
свойства на елемент до фиксирана стойност, така че елементът ще се разшири хоризонтално, за да използва съответно останалото хоризонтално пространство.
За нашия случай на употреба трябва да използваме вертикално разширение.
margin
Основната скролируема област на съдържанието може просто да разчита на позициониране по подразбиране (статично), при което елементите се изобразяват в ред, както се появяват в потока на документите. Тъй като всичко останало на нашата страница е във фиксирана позиция, този елемент е единственият, който е в потока на документите. В резултат на това всичко, което трябва да направим, за да го позиционираме правилно, е да го определим #main { margin: 6em 0 4em 20em; }
свойство за избягване на припокриване с фиксирания заглавен, долен колонтитул и nav / subnav:
5em
И с това сме изпълнили основните изисквания за оформление на нашия случай на използване, използвайки CSS2, но все пак трябва да удовлетворим допълнителните изисквания за динамична функционалност.
Изискванията заявиха, че менюто ни за навигация по подразбиране ще показва само икони, но ще може да бъде разширено, за да показва и текст (и след това може да бъде свито, за да показва само икони).
Нека започнем с просто добавяне на #nav { left: 0; width: 5em; &.expanded { /* Sass notation */ width: 10em; } }
до ширината на менюто за навигация, когато е разширено. Ще направим това, като създадем „разширен“ CSS клас, който можем динамично да добавяме или премахваме от елемента на менюто за навигация:
$('.layout-classic #nav').on('click', 'li.nav-toggle', function() { $('#nav’').toggleClass('expanded'); });
Ето пример за кода на JavaScript (в този пример използваме jQuery), който може да се използва за динамично превключване на менюто за навигация между разширен и свит режим, въз основа на потребителския клик върху иконата за превключване на навигацията:
#subnav { left: 6em; width: 13em; &.expanded { left: 11em; /* move it on over */ } } #main { margin: 6em 0 4em 20; z-index: 10; &.expanded { margin-left: 25em; /* move it on over */ } }
И с това, нашето меню за навигация вече може динамично да се разширява или свива. Страхотен.
Е, нещо страхотно, но не съвсем. Въпреки че навигационното меню вече може да се разширява и свива, то не играе добре с останалата част от страницата. Разширеното меню за навигация вече припокрива subnav, което определено не е желаното поведение.
Това разкрива едно от ключовите ограничения на CSS2; а именно, има начин твърде много, което трябва да бъде кодирано твърдо с фиксирани стойности на позицията. В резултат на това за останалите елементи на страницата, които трябва да бъдат преместени, за да поместят разширеното меню за навигация, трябва да дефинираме допълнителен „Разширени“ CSS класове с още повече стойности на фиксирана позиция.
$('.layout-classic #nav').on('click', 'li.nav-toggle', function() { $('#nav, #subnav, #main').toggleClass('expanded'); });
След това трябва да разширим нашия JavaScript код, за да добавим динамична настройка и на тези други елементи, когато превключвателят за навигация е щракнат от потребителя:
display: none
Добре, това работи по-добре.
Сега нека разгледаме изискването за наличието на няколко страници, които скриват подменюто. По-конкретно, ние искаме подменюто за навигация да бъде скрито, когато потребителят щракне върху иконата „потребители“ в основната навигационна област.
Така че първо ще създадем нов клас „скрит“, който се прилага .hidden { display: none; }
:
#subnav
И отново ще използваме JavaScript (jQuery), за да приложим „скрития“ CSS клас към $('#nav.fa-user').on('click', function() { $('#subnav').toggleClass('hidden'); });
елемент, когато потребителят щракне върху иконата на потребителите:
#subnav
С това допълнение, #subnav
елементът се скрива правилно, когато потребителят щракне върху иконата „потребители“, но мястото, което беше заемало, остава неизползвано , вместо другите елементи да се разширяват, за да използват пространството, освободено от #subnav
елемент.
За да получим желаното поведение, когато скриваме main
елемент, ще използваме един от по-малко известните, но изключително полезни CSS селектори, известни като съседен селектор за братя и сестри .
The съседен селектор за братя и сестри ви позволява да посочите два елемента, като изберете само онези екземпляри на втория елемент, които следват непосредствено посочения първи елемент.
Например по-долу ще изберете само тези елементи с ID subnav
че веднага следвайте елемент с ID #subnav + #main { margin-left: 20em; }
:
#main
Горният CSS фрагмент задава левия поле на 20em
до #subnav
ако и само ако той веднага следва показания #nav
.
Ако обаче expanded
се разширява (което кара класът #main
да бъде добавен и към #main
, въз основа на по-ранния ни код), преместваме левия поле на #subnav + #main.expanded { margin-left: 25em; }
до 25ем.
#subnav
И, ако #main
е скрито, преместваме левия поле на #nav
чак до 6em, за да бъде точно до #subnav.hidden + #main { margin-left: 6em; }
:
#subnav
(Забележка: Един недостатък на използването на съседния селектор на братя и сестри е, че ни принуждава винаги да имаме #subnav
присъствие в DOM, независимо дали се показва или не.)
И накрая, ако #nav
е скрит и #main
се разширява, задаваме левия поле на 11em
в #subnav.hidden + #main.expanded { margin-left: 11em; }
:
calc()
Това ни позволява да свързваме нещата без никакъв тежък JavaScript код, но също така можем да видим колко сложен може да стане този код, ако добавим повече елементи към страницата. Отново виждаме, че с CSS2, много на твърдо кодиране на стойностите на позицията е необходимо, за да накараме нещата да работят правилно.
CSS3 предлага значително подобрена функционалност и техники за оформление, които го правят много по-лесен за използване и много по-малко зависим от твърдо кодирани стойности. CSS3 по своята същност е проектиран да поддържа по-динамично поведение и в този смисъл е по-„програмируем“. Нека разгледаме някои от тези нови възможности, тъй като те са свързани с нашия случай на употреба.
calc()
ФункцияНовото CSS3 calc()
функция може да се използва за динамично изчисляване на стойностите на свойствата на CSS (имайте предвид обаче, че подкрепата варира в браузърите). Изразът, предоставен на +
функция може да бъде всеки прост израз, съчетаващ основните аритметични оператори (-
, *
, /
, calc()
), използвайки стандартни правила за приоритет на оператора.
Използване на #nav, #subnav { position: fixed; height: calc(100% - 10em); /* replaces */ z-index: 20; }
функция може да помогне за избягване на голяма част от твърдото кодиране на стойности, изисквани от CSS2. В нашия случай това ни позволява да постигнем разширяване на CSS по-динамично. Например:
height
С горното calc()
спецификация с помощта на top:6em
функция, постигаме същия резултат като в CSS2 с bottom:4em
и top
, но по много по-гъвкав и адаптивен начин и без да се налага твърдо кодиране bottom
и display
стойности на позицията.
Flexbox е ново оформление, въведено в CSS3 ( поддръжката варира в различните браузъри ). Оформлението на flexbox улеснява подреждането на елементи на страница по начин, който се държи предсказуемо при различни размери на екрана, резолюции и устройства. Следователно е особено полезно в контекста на отзивчив уеб дизайн .
Основните характеристики включват:
Flexbox представя свой собствен уникален набор от термини и понятия. Някои от тях включват:
flex
свойството е зададено на inline-flex
или flex-directio
който служи като елемент на контейнера за гъвкави елементи.flex-wrap
n който обозначава основна ос покрай които са изложени гъвкавите предмети. The кръстосана ос е оста, перпендикулярна на главната ос.main size
Имот.cross size
и .layout-flexbox { display: flex; flex-direction: column; }
, които указват съответно размерите на главната ос и напречната ос на гъвкавия контейнер.Добре, така че с това кратко въведение, ето алтернативната маркировка, която можем да използваме, ако използваме flexbox оформление:
content-area
За примерния ни случай на употреба основното ни оформление (заглавна част, съдържание, долен колонтитул) е вертикално, така че ще настроим флексбокса да използва оформление на колона:
#nav
Въпреки че основното ни оформление е вертикално, елементите в нашата област на съдържание (nav, subnav, main) са разположени хоризонтално. Всеки гъвкав контейнер може да дефинира само една посока (т.е. оформлението му трябва да бъде хоризонтално или вертикално). Следователно, когато оформлението изисква повече от това (често срещаният случай е за оформление на приложение), можем да вложим множество контейнери един в друг, всеки с различно насочено оформление.
Ето защо добавихме допълнителен контейнер (който нарекох #subnav
) обвивка #main
, flex
и flex: ;
. По този начин цялостното оформление може да бъде вертикално, докато съдържанието на съдържанието може да бъде разположено хоризонтално.
Сега, за да позиционираме нашите гъвкави елементи, ще използваме свойството flex-grow
това е стенография за flex-shrink
. Тези три гъвкави свойства са тези, които определят как нашите гъвкави елементи разпределят свободното пространство, оставащо между тях, в посока на потока, както следва:
Настройка #header { flex: 0 0 5em; } #footer { flex: 0 0 3em; }
и flex-grow
и двете на нула означава, че размерът на елемента е фиксиран и няма да расте или да се свива, за да побере, че има повече или по-малко свободно пространство. Това правим за нашия горен и долен колонтитул, тъй като те имат фиксиран размер:
flex-shrink
За да може даден елемент да заеме цялото свободно място, задайте неговия flex-basis
и auto
стойности едновременно на 1 и задайте неговите content-area
стойност до display: flex
. Това правим за областта на съдържанието, тъй като искаме да заема цялото налично свободно пространство.
И както казахме по-рано, ние искаме елементите вътре flex-direction: row;
да се разположи в посока на реда, така че ще добавим #nav
; и #subnav
. Това прави content-area нов гъвкав контейнер за content-area
, .content-area { display: flex; flex-direction: row; flex: 1 1 auto; /* take up all available space */ margin: 1em 0; min-height: 0; /* fixes FF issue with minimum height */ }
и `#main.
Така че ето какво завършваме за CSS за #nav
:
#subnav
В областта на съдържанието и двете flex
и #nav { flex: 0 0 5em; margin-right: 1em; overflow-y: auto; } #subnav { flex: 0 0 13em; overflow-y: auto; margin-right: 1em; }
имат фиксирани размери, така че просто задаваме overflow-y: hidden
собственост съответно:
#main
(Обърнете внимание, че съм добавил #main { flex: 1 1 auto; overflow-y: auto; }
към тези CSS спецификации, за да преодолея съдържанието, което надвишава и превишава височината на контейнера. Chrome всъщност не се нуждае от това, но FireFox го прави.)
layout-flexbox
ще заеме останалото свободно пространство:
layout-classic
Всичко това изглежда добре, така че нека сега добавим нашето динамично поведение към това и да видим как протича това.
JavaScript е идентичен с това, което сме имали преди (с изключение на това, класът на контейнера на CSS елемент, който посочваме, е $('.layout-flexbox #nav’).on('click', 'li.nav-toggle', function() { $('#nav').toggleClass('expanded'); });
докато преди това беше expanded
):
#nav { flex: 0 0 5em; /* collapsed size */ margin-right: 1em; overflow-y: auto; &.expanded { flex: 0 0 10em; /* expanded size */ } }
Добавяме display
клас към CSS, както следва:
fr
И вуаля!
Обърнете внимание, че този път не е необходимо да уведомяваме други елементи за промяната на ширината, тъй като оформлението на flexbox обработва всичко това вместо нас.
Единственото, което остава тогава, е да скриете под навигацията. И познай какво? Това „просто работи“, без никакви допълнителни промени, използвайки същия JavaScript код като преди. Flexbox знае за свободното пространство и автоматично кара оформлението ни да работи без допълнителен код. Много готино.
Flexbox предлага и някои интересни начини за центриране както на вертикални, така и на хоризонтални елементи. Тук осъзнаваме колко е важно презентационният език да включва понятието свободно пространство и колко мащабируем може да стане нашият код, използвайки тези видове техники. От друга страна, понятията и нотациите тук могат да отнемат малко повече, за да овладеят, отколкото класическия CSS.
Ако Flexbox Layout е в предния ръб на CSS3, тогава Grid Layout може да се каже, че е в неговия кървящ ръб. Спецификацията на W3C все още е в чернови състояние и все още има доста ограничена поддръжка на браузъра . (Активиран е в Chrome чрез флага „експериментални функции на уеб платформа“ в chrome: // flags ).
Въпреки това, аз лично не считам този проект за революционен. По-скоро като Принципи на HTML5 дизайн състояние: „Когато дадена практика вече е широко разпространена сред авторите, помислете дали да не я възприемете, вместо да я забраните или да измислите нещо ново.“
Съответно, мрежите, базирани на маркиране, се използват отдавна, така че сега CSS Grid Layout наистина просто следва същата парадигма, предлагайки всичките си предимства и много повече в презентационния слой без изисквания за маркиране.
Общата идея е да имаме предварително дефинирано, фиксирано или гъвкаво оформление на мрежата, където можем да позиционираме нашите елементи. Подобно на flexbox, той също работи на принципа на свободното пространство и ни позволява да дефинираме както вертикални, така и хоризонтални „посоки“ в един и същи елемент, което носи предимства в размера на кода и гъвкавостта.
Оформлението на мрежата представя 2 вида мрежи; а именно, изрично и имплицитен . За опростяване ще се съсредоточим върху явни мрежи в това.
Подобно на flexbox, оформлението на Grid представя свой собствен уникален набор от термини и концепции. Някои от тях включват:
.layout-grid { display: grid; grid-template-columns: auto 0 auto 1em 1fr; grid-template-rows: 5em 1em 1fr 1em 3em; }
свойство, зададено на „мрежа“ или „вградена мрежа“, в което съдържащите се елементи са разположени чрез позициониране и подравняване към предварително дефинирана мрежа (изричен режим). Мрежата е пресичащ се набор от хоризонтални и вертикални линии на мрежата, които разделят пространството на мрежата на контейнера на мрежови клетки. Има два комплекта решетъчни линии; една за дефиниране на колоните и една ортогонална към нея за дефиниране на редовете.display: grid;
единица, която представлява част от свободното пространство в мрежата контейнер.
Ето алтернативното маркиране, което можем да използваме, ако използваме оформление на мрежата:
grid-template-columns
Имайте предвид, че с това оформление го правим не се нуждаем от допълнителна обвивка за областта на съдържанието, както направихме за flexbox, тъй като този тип оформление ни позволява да дефинираме обозначението на пространството на елемента в двете посоки в един и същ контейнер на мрежата.
Нека да разгледаме CSS сега:
grid-template-rows
Определихме grid-template-columns: auto 0 auto 1em 1fr;
на нашия контейнер. auto
и #nav
свойствата са посочени като списък на интервалите между решетките. С други думи, тези стойности не са позицията на линиите на мрежата; по-скоро те представляват количество пространство между две писти.
Имайте предвид, че мерните единици могат да бъдат посочени като:
Така че с #subnav
ще имаме:
auto
ширина (#subnav
интервал)1em
е на ниво елемент, тъй като може да присъства или не, по този начин избягваме да имаме двоен улей)1fr
ширина (#main
интервал)auto
#nav
за #subnav
(ще отнеме цялото останало място)Тук използваме интензивно grid-template-rows: 5em 1em 1fr 1em 3em;
стойност за пистата, която ни позволява да имаме динамични колони, където позицията и размерът на редовете се определят от максималното им съдържание. (Следователно ще трябва да посочим размерите на елементите #header
и #footer
, което ще направим скоро.)
По същия начин за редовите редове имаме 1em
който задава нашите #header { grid-column: 1 / 6; grid-row: 1 / 2; } #footer { grid-column: 1 / 6; grid-row: 5 / 6; } #main { grid-column: 5 / 6; grid-row: 3 / 4; overflow-y: auto; }
и grid-column
да бъдат фиксирани и всички елементи между тях да използват останалото свободно пространство, докато използвате grid-row
улуци.
Сега нека видим как поставяме действителните елементи, които да бъдат позиционирани в нашата дефинирана мрежа:
grid-column-start
Това указва, че искаме заглавката ни да е между решетката 1 и 6 (пълна ширина) и между редовете 1 и 2 на мрежата за нашите редове. Същото е и за долния колонтитул, но между последните два реда (а не първите два). И основната площ е зададена подходящо за пространството, което трябва да заема.
Имайте предвид, че grid-column-end
и grid-row-start
свойствата са стенография за посочване на grid-row-end
/ #nav
и #subnav
/ #nav
, съответно.
Добре, така че обратно към #subnav
и #nav { width: 5em; grid-column: 1 / 2; grid-row: 3 / 4; &.expanded { width: 10em; } } #subnav { grid-column: 3 / 4; grid-row: 3 / 4; width: 13em; /* track has gutter of 0, so add margin here */ margin-left: 1em; }
. Тъй като преди това поставихме #nav
и #subnav
в пистата с автоматични стойности, трябва да посочим колко широки са тези елементи (същото за разширения режим, ние просто променяме ширината му, а Grid Layout се грижи за останалото).
Така че сега можем да превключваме нашите
|_+_|и също така скрийте / премахнете
|_+_|и всичко работи перфектно! Оформлението на мрежата също ни позволява да използваме псевдоними за нашите линии, така че в крайна сметка променящите се мрежи няма да пробият кода, тъй като той е съпоставен с име, а не с решетка. Определено очакваме с нетърпение това да бъде по-широко подкрепено от повече браузъри.
Дори и с класическите CSS техники може да се постигне много повече, отколкото много уеб разработчици осъзнават или се възползват. Въпреки това, голяма част от това може да бъде доста досадно и може да включва твърдо кодиране на стойности многократно в таблица със стилове.
CSS3 започна да доставя много по-усъвършенствани и гъвкави техники за оформление, които са значително по-лесни за програмиране и които избягват голяма част от предишните спецификации на CSS.
Овладяването на тези техники и парадигми - както за CSS2, така и за CSS3 - е от съществено значение за оползотворяване на всичко, което CSS може да предложи, за да оптимизирате както потребителския опит, така и качеството на вашия код. Тази статия наистина представлява само върха на айсберга на всичко, което трябва да се научи, и всичко, което може да бъде постигнато със силата и гъвкавостта на CSS. Имайте го!
Свързани: * Изследване на SMACSS: Мащабируема и модулна архитектура за CSS *