Кругова навігація на CSS

17

Від автора: Підручник про те, як створити кругову навігацію за допомогою перетворень CSS.

У цьому уроці я покажу вам, як за допомогою перетворень CSS створити кругову навігацію. Я проведу вас по етапах створення потрібних стилів і поясню стоїть за ними математику (фу-у-у!) і просту логіку, щоб у вас склалося чітке розуміння цієї методики. Як я вже говорив, при створенні цих стилів задіюється трохи базової математики поряд з перетвореннями CSS. Але не турбуйтеся, математика насправді дуже проста і я буду її покроково пояснювати.

Кругова навігація на CSSКругова навігація на CSS

Також хочу віддати належне за початкове створення цієї техніки Не Тюдор (Ana Tudor). Я злегка підкоригував її для отримання потрібних мені результатів, що, сподіваюся, і ви зможете зробити до кінця цього підручника: отримати повне і чітке розуміння цього методу і повозитися з ним, створюючи власні стилі. Отже, давайте почнемо без подальших зволікань!

РОЗМІТКА

Ми збираємося будувати навігацію, тому почнемо з нормальною навігаційної структури. Нам знадобиться div для утримання неупорядкованого списку елементів, кнопка запуску відкриття і закриття навігації, список елементів, а для першого демо-приклад – додатковий оверлей, щоб прикривати сторінку при відкритій навігації.

+

Використовувані в цьому демо-прикладі іконки взяті з Font Awesome.

МАТЕМАТИКА, ЩО СТОЇТЬ ЗА ПЕРЕТВОРЕННЯМИ CSS

Пояснювати математику краще всього в зоровій, а не в письмовій формі. Тому почнемо з логіки, по мірі просування вперед застосуємо математику, а після закінчення пояснень перейдемо до кодування, до цього моменту ви будете в точності знати, яке правило CSS що робить. Спочатку давайте розберемося, що таке «центральний кут». Це візуальне уявлення, за яким слід просте пояснення:

Кругова навігація на CSS

Припустимо, вам потрібно розподілити всі елементи навігації в півколі, як у створюваній нами прикладі, і у вас в списку навігації шість пунктів, тоді в кожного кута буде центральний кут в: 180гр. / 6 = 30гр.

Якщо ви хочете, щоб елементи зайняли всю окружність цілком, і у вас їх шість, то центральний кут для кожного пункту складе: 360гр. / 6 = 60гр.

І так далі. Ви вважаєте значення потрібного вам центрального кута, і з цього моменту для фактичного створення цих кутів ми починаємо застосовувати до перетворень CSS просту математику. Для побудови кута зі значенням, рівним потрібного нам значення центрального кута, нам доведеться нахилити елементи (за допомогою функції CSS skew()): 90гр. – x гр., де x – це значення потрібного нам центрального кута.

Легко. Але в даному випадку все вміст всередині пунктів списку також нахилиться, і контент буде виглядати безладно, що нам не потрібно, тому «усунемо нахил» прив’язки всередині кожного пункту, щоб контент добре виглядав, але до цього ми доберемося через хвилину.

Я зробив живий інтерактивний демо-приклад, де показано, як покроково до елементів навігації застосовуються перетворення, щоб ви отримали чітке розуміння того, що ми будемо кодувати. (Зверніть увагу, що аналіз в демо-прикладі порядком етапів може злегка відрізнятися від тих кроків, які ми зробимо в підручнику)

Зараз ви, можливо, захочете переглянути покроковий демо-приклад, щоб отримати чітке уявлення про наших подальших діях. Я також додав в демо розбір того, що відбувається на кожному кроці, тому перегляд прикладу і отримання про це подання займе всього одну хвилину. Демо-приклад можна програти від початку до кінця, скориставшись кнопкою «Почати демо» (Start Demo), або керувати пересуванням від етапу до етапу з допомогою кнопки «Наступний крок» (Next Step), а перезапустити його можна в будь-який момент з кнопки «Повернення» (Reset).

Дивитися інтерактивний демо-приклад

Ось скріншоти етапів, які ви побачите в прикладі:

Початковий стан:

Кругова навігація на CSS

Крок 1:

Кругова навігація на CSS

Крок 2:

Кругова навігація на CSS

Крок 3:

Кругова навігація на CSS

Крок 4:

Кругова навігація на CSS

Крок 5:

Кругова навігація на CSS

Крок 6:

Кругова навігація на CSS

Отже, давайте ще раз пройдемося по них:

Нам доведеться абсолютно розташувати всі елементи всередині контейнера.

Ми встановимо початком перетворення кожного елемента нижній правий кут.

Потім транслюємо елементи вгору і вліво рівно настільки, щоб їх початок перетворення збігався з центром їх контейнера.

Далі повертаємо елементи за годинниковою стрілкою на їх місце за допомогою наступної формули: Кожен елемент з індексом i ми обертаємо на: i * x , де x знову значення центрального кута

Потім зводимо їх для отримання потрібного центрального кута (застосовуючи вищенаведену формулу)

У нашому прикладі п’ять пунктів навігації, тобто п’ять центральних кутів, де нам потрібно прикрити тільки верхню половину окружності, тому відповідно до объясненной вищою математикою кожен елемент отримає центральний кут в 36 гр., але в нашому прикладі я встановив значення центрального кута в 40гр. (тому що так забезпечується збільшена область клацання), так що сума всіх кутів дорівнює 5 * 40 = 200гр., що більше 180гр. В даному випадку все, що ми робимо – це обертаємо елементи «назад» проти годинникової стрілки (200-180)/2 гр. для того, щоб переконатися, що вони врівноважені з обох сторін.

На даний момент ми вже створили потрібні центральні кути і позиціонували їх. Але нахил пунктів списку також викликав нахил їх вмісту (тегів-посилань) і, таким чином – спотворення їх вмісту, тому останнім математичне правило, яке ми тут застосуємо (фу!) – це те, яке гарантує, що теги-посилання не буде перекручено і їх контент буде видимим. Ось воно:

Ви прибираєте нахил посилань, тобто нахиляєте його з допомогою протилежного значення того, яке ви використовували для нахилу пунктів списку, а потім назад перевертаєте посилання відповідно до значення:

— [90 – (x/2) ] , де x-значення центрального кута

Отже, значення центрального кута в 40гр. нам потрібно нахилити посилання на 40гр. і повернути їх на:

-[ 90 – (40/2) ] = -70 гр.

Посилання розташовані абсолютно межах своїх батьківських елементів, і переповнення overflow елементів списку встановлено на прихований (hidden), тобто ця частина посилань відсікається, тому для гарантії розташування текстового/іконного вмісту посилань поза їх видимої частини ми встановимо вирівнювання тексту по центру.

Ось і вся математика, потрібна вам для створення «скибок» всередині навігації! Ну нарешті-то, вірно? Отже, давайте швиденько ще раз повторимо:

Поверніть елементи в їх положення: кут y = i * x (де i = вказівник елемента, а x = значення центрального кута)

Нахиліть їх на 90гр. – x (де x – це знову значення центрального кута)

Розгорніть елементи в протилежному напрямку, якщо/коли потрібно їх збалансувати (цей крок насправді об’єднаний з попереднім, ви віднімаєте значення, на яке потрібно розгорнути кути назад, значення кута, на яке ви обертаєте)

«Усуньте нахил» і «поверніть назад» ссыдки всередині них (і встановіть вирівнювання тексту по центру)

Звичайно, я пропустив ту частину, де ви переміщаєте пункти списку так, щоб початок їх перетворення співпало з центром контейнера (як показано в демо-прикладі). І це в загальному все, що потрібно для створення кутів, але не все – для створення всієї навігації. Залишилися кілька простих кроків, і вони багато в чому є звичайним призначенням стилів, тому давайте почнемо працювати з CSS і обговоримо все по мірі просування!

CSS

Спочатку призначимо стилі першого демо-наприклад.

Кругова навігація на CSS

Ми збираємося скористатися класами Modernizr’а, застосувавши їх до тегу body, щоб вибрати підтримують і неподдерживающие браузери, а також забезпечити просту загальну альтернативу для старих браузерів, які не підтримують перетворення CSS.

Почнемо зі стилів обгортки навігації. Вона отримає фіксоване положення внизу в центрі сторінки і у вихідному положенні буде зменшено, а потім при клацанні по кнопці «open» буде відкриватися/збільшуватися.

.csstransforms .cn-wrapper {
font-size:1em;
width: 26em;
height: 26em;
overflow: hidden;
position: fixed;
z-index: 10;
bottom: -13em;
left: 50%;
border-radius: 50%;
margin-left: -13em;
transform: scale(0.1);
transition: all .3s ease;
}
/* клас, застосований до контейнера через JavaScript, який буде збільшувати навігацію*/
.csstransforms .opened-nav {
border-radius: 50%;
transform: scale(1);
}

Також призначимо стиль і місце кнопці, запускає відкриття і закриття нашої навігації.

.cn-button {
border:none;
background:none;
color: white;
text-align: Center;
font-size: 1.5 em;
padding-bottom: 1em;
height: 3.5 em;
width: 3.5 em;
background-color: #111;
position: fixed;
left: 50%;
margin-left: -1.75 em;
bottom: -1.75 em;
border-radius: 50%;
cursor: pointer;
z-index: 11
}
.cn-button:hover,
.cn-button:active,
.cn-button:focus{
background-color: #222;
}

При відкритій навігації оверлей покриває сторінку. Ось стилі оверлея.

.cn-overlay{
width:100%
height:100%;
background-color: rgba(0,0,0,0.6);
position:fixed;
top:0;
left:0;
bottom:0;
right:0;
opacity:0;
transition: all .3s ease;
z-index:2;
pointer-events:none;
}
/* Клас, доданий до оверлею через JavaScript для того, щоб показувати його при відкритій навігації */
.cn-overlay.on-overlay{
pointer-events:auto;
opacity:1;
}

Тепер визначимо стилі елементів навігації та їх посиланнями, застосувавши перетворення на основі объясненной вище логіки і математики.

.csstransforms .cn-wrapper li {
position: absolute;
font-size: 1.5 em;
width: 10em;
height: 10em;
transform-origin: 100% 100%;
overflow: hidden;
left: 50%;
top: 50%;
margin-top: -1.3 em;
margin-left: -10em;
transition: border .3s ease;
}
.csstransforms .cn-wrapper li a {
display: block;
font-size: 1.18 em;
height: 14.5 em;
width: 14.5 em;
position: absolute;
bottom: -7.25 em;
right: -7.25 em;
border-radius: 50%;
text-decoration: none;
color: #fff;
padding-top: 1.8 em;
text-align: center;
transform: skew(-50deg) rotate(-70deg) scale(1);
transition: opacity 0.3 s, color 0.3 s;
}
.csstransforms .cn-wrapper li a span {
font-size: 1.1 em;
opacity: 0.7;
}
/* для центрального кута x пункти списку повинні бути скошені на 90-x градусів
У нашому випадку x=40гр., тому кут скосу становить 50грн.
Елементи потрібно повернути на x мінус (сума кутів — 180)2 (для даного прикладу) */
.csstransforms .cn-wrapper li:first-child {
transform: rotate(-10deg) skew(50deg);
}
.csstransforms .cn-wrapper li:nth-child(2) {
transform: rotate(30deg) skew(50deg);
}
.csstransforms .cn-wrapper li:nth-child(3) {
transform: rotate(70deg) skew(50deg)
}
.csstransforms .cn-wrapper li:nth-child(4) {
transform: rotate(110deg) skew(50deg);
}
.csstransforms .cn-wrapper li:nth-child(5) {
transform: rotate(150deg) skew(50deg);
}
.csstransforms .cn-wrapper li:nth-child(odd) a {
background-color: #a11313;
background-color: # hsla-color hsla(0, 88%, 63%, 1);
}
.csstransforms .cn-wrapper li:nth-child(even) a {
background-color: #a61414;
background-color: # hsla-color hsla(0, 88%, 65%, 1);
}
/*активний стиль */
.csstransforms .cn-wrapper li.active a {
background-color: #b31515;
background-color: # hsla-color hsla(0, 88%, 70%, 1);
}
/*стиль при проведенні мишею */
.csstransforms .cn-wrapper li:not(.active) a:hover,
.csstransforms .cn-wrapper li:not(.active) a:active,
.csstransforms .cn-wrapper li:not(.active) a:focus {
background-color: #b31515;
background-color: # hsla-color hsla(0, 88%, 70%, 1);
}

Ми забезпечимо просту альтернативу для тих браузерів, які не підтримують перетворення CSS.

.no-csstransforms .cn-wrapper{
font-size:1em;
height:5em;
width:25.15 em;
bottom:0;
margin-left: -12.5 em;
overflow: hidden;
position: fixed;
z-index: 10;
left:50%;
border:1px solid #ddd;
}
.no-csstransforms .cn-button{
display:none;
}
.no-csstransforms .cn-wrapper li{
position:static;
float:left;
font-size:1em;
height:5em;
width:5em;
background-color: #eee;
text-align:center;
line-height:5em;
}
.no-csstransforms .cn-wrapper li a{
display:block;
width:100%;
height:100%;
text-decoration:none;
color:inherit;
font-size:1.3 em;
border-right: 1px solid #ddd;
}
.no-csstransforms .cn-wrapper li a:last-child{
border:none;
}
.no-csstransforms .cn-wrapper li a:hover,
.no-csstransforms .cn-wrapper li a:active,
.no-csstransforms .cn-wrapper li a:focus{
background-color: white;
}
.no-csstransforms .cn-wrapper li.active a {
background-color: #6F325C;
color: #fff;
}

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

@media screen and (max-width:480px){
.csstransforms .cn-wrapper{
font-size:.68em;
}
.cn-button{
font-size:1em;
}
.csstransforms .cn-wrapper li {
font-size:1.52 em;
}
}
@media screen and (max-width:320px){
.no-csstransforms .cn-wrapper{
width:15.15 px;
margin-left: -7.5 em;
}
.no-csstransforms .cn-wrapper li{
height:3em;
width:3em;
}
}

Ось і все, що стосується першого демо-приклад! Давайте перейдемо до наступного.

Кругова навігація на CSS

Другий стиль з окружністю відрізняється від першого, але всі потрібні для його створення математика, логіка і перетворення дуже схожі на попередній, за винятком трьох відмінностей. Тому ми не будемо заново все пояснювати, просто розкриємо три потрібних для нього відрізняються етапу.

Давайте знову візьмемо наведений вище приклад і змінимо одне маленьке просте правило CSS, і подивимося, яке відміну воно створить в обрисах елементів. Ми застосуємо фон з радіальним градієнтом до посилань з прозорим фоновим кольором. Результат буде такий:

Кругова навігація на CSS

Бачите, куди ми пройшли. Далі ми збираємося додати проміжки між елементами, злегка змінивши кут обертання кожного з них. Також видалимо фонові кольори пунктів списку, контейнера і використовуваних рамок, і зменшимо верхній відступ посилань, щоб підняти іконки трохи вгору і відцентрувати їх по вертикалі. Отриманий результат виглядає так:

Кругова навігація на CSS

Бачите, навігація вже починає виглядати по-іншому; ми пройшли половину шляху. Нам потрібно зробити ще одну важливу річ. В поточному стані цього стилю область клацання посилань все ще більше, ніж потрібно. Нам потрібно, щоб підвладній клацання/проведення мишею була тільки кольорова частину показаній на зображенні навігації. На зображенні внизу показана додаткова область клацання посилань.

Кругова навігація на CSS

При проведенні мишею над показаної на зображенні червоної областю, яка є нижньою частиною посилань, запускається стан проведення мишею, і це нормально, але так як нам потрібно, щоб виглядало все так, наче посилання – це тільки пурпурова область, то слід запобігти запуск подій миші в нижній частині посилань. Для цього ми скористаємося «накладкою», яку помістимо поверх центру навігаційного контейнера, що буде представляти із себе фігуру у вигляді кола, що покриває нижні частини посилань і, таким чином, блокує події миші в цих областях. Ми застосуємо для цього псевдоэлемент, щоб не додавати у свою розмітку зайві порожні теги.

Отже, застосувавши до свого CSS ці три кроки і змінивши загальні стилі (кольори та розміри) навігації та її елементів так, щоб ті виглядали як на попередньому зображенні, у нас вийде в підсумку наступний CSS:

.csstransforms .cn-wrapper {
position: absolute;
top: 100%;
left: 50%;
z-index: 10;
margin-top: -13em;
margin-left: -13.5 em;
width: 27em;
height: 27em;
border-radius: 50%;
background: transparent;
opacity: 0;
transition: all .3s ease 0.3 s;
transform: scale(0.1);
pointer-events: none;
overflow: hidden;
}
/*закрийте від клацань зайвий простір прив’язок*/
.csstransforms .cn-wrapper:after{
color: transparent;
content:».»;
display:block;
font-size:2em;
width:6.2 em;
height:6.2 em;
position: absolute;
left: 50%;
margin-left: -3.1 em;
top:50%;
margin-top: -3.1 em;
border-radius: 50%;
z-index:10;
}
.csstransforms .cn-wrapper li {
position: absolute;
top: 50%;
left: 50%;
overflow: hidden;
margin-top: -1.3 em;
margin-left: -10em;
width: 10em;
height: 10em;
font-size: 1.5 em;
transition: all .3s ease;
transform: rotate(76deg) skew(60deg);
transform-origin: 100% 100%;
pointer-events: none;
}
.csstransforms .cn-wrapper li a {
position: absolute;
right: -7.25 em;
bottom: -7.25 em;
display: block;
width: 14.5 em;
height: 14.5 em;
border-radius: 50%;
background: #429a67;
background: radial-gradient(transparent 35%, #429a67 35%);
color: #fff;
text-align: center;
text-decoration: none;
font-size: 1.2 em;
line-height: 2;
transition: all .3s ease;
transform: skew(-60deg) rotate(-75deg) scale(1);
pointer-events: auto;
}
.csstransforms .cn-wrapper li a span {
position: relative;
top: 1.8 em;
display: block;
font-size: .5em;
font-weight: 700;
text-transform: uppercase;
}
.csstransforms .cn-wrapper li a:hover,
.csstransforms .cn-wrapper li a:active,
.csstransforms .cn-wrapper li a:focus {
background: radial-gradient(transparent 35%, #449e6a 35%);
}

Потрібно, щоб елементи навігації у другому демо розкривалися при її відкритті з ефектом віяла. Щоб його досягти, ми позиціонуємо елементи в тому ж місці і з тим же поворотом/нахилом rotate(76deg) skew(60deg). З допомогою призупинення перетворення ми даємо елементам можливість розкриватися після того, як збільшимо обгортку. При закриття навігації почекаємо, поки елементи повернуться назад, перед тим, як знову зменшити обгортку. При клацанні по кнопці «open» ми розкриємо елементи, повернувши кожен з них в їх остаточну позицію в окружності.

.csstransforms .opened-nav {
border-radius: 50%;
opacity: 1;
transition: all .3s ease;
transform: scale(1);
pointer-events: auto;
}
.csstransforms .opened-nav li {
transition: all .3s ease .3s;
}
.csstransforms .opened-nav li:first-child {
transform: rotate(-20deg) skew(60deg);
}
.csstransforms .opened-nav li:nth-child(2) {
transform: rotate(12deg) skew(60deg);
}
.csstransforms .opened-nav li:nth-child(3) {
transform: rotate(44deg) skew(60deg);
}
.csstransforms .opened-nav li:nth-child(4) {
transform: rotate(76deg) skew(60deg);
}
.csstransforms .opened-nav li:nth-child(5) {
transform: rotate(108deg) skew(60deg);
}
.csstransforms .opened-nav li:nth-child(6) {
transform: rotate(140deg) skew(60deg);
}
.csstransforms .opened-nav li:nth-child(7) {
transform: rotate(172deg) skew(60deg);
}

Звичайно, ми також забезпечимо неподдерживающие браузери загальним альтернативним варіантом.

.no-csstransforms .cn-wrapper{
margin:10em auto;
overflow:hidden;
text-align:center;
padding:1em;
}
.no-csstransforms .cn-wrapper ul{
display:inline-block;
}
.no-csstransforms li{
font-size:1em;
width:5em;
height:5em;
float:left;
line-height:5em;
text-align:center;
background-color: #fff;
}
.no-csstransforms li a{
display:block;
height:100%;
width:100%;
text-decoration: none;
color: inherit;
}
.no-csstransforms .cn-wrapper li a:hover,
.no-csstransforms .cn-wrapper li a:active,
.no-csstransforms .cn-wrapper li a:focus{
background-color: #f8f8f8;
}
.no-csstransforms .cn-wrapper li.active a {
background-color: #6F325C;
color: #fff;
}
.no-csstransforms .cn-button{
display:none;
}

І, крім того, навігація повинна бути адаптивною, тому на маленьких екранах ми зменшимо її. Ось адаптивні стилі як для стилю колу, так і для простого виду.

@media only screen and (max-width: 620px) {
.no-csstransforms li{
width:4em;
height:4em;
line-height:4em;
}
}
@media only screen and (max-width: 500px) {
.no-ccstransforms .cn-wrapper{
padding:.5em;
}
.no-csstransforms .cn-wrapper li{
font-size:.9em;
width:4em;
height:4em;
line-height:4em;
}
}
@media only screen and (max-width: 480px) {
.csstransforms .cn-wrapper{
font-size: .68em;
}
.cn-button{
font-size:1em;
}
}
@media only screen and (max-width:420px){
.no-csstransforms .cn-wrapper li{
width:100%;
height:3em;
line-height:3em;
}
}

Ось, загалом-то, і весь необхідний для створення цих стилів CSS!

JAVASCRIPT

У цих демо ми не користуємося каркасами-фреймами JavaScript’а. Для додавання і видалення класів я застосую Classie.js Давіда Де Сандро (David De Sandro). І, нарешті, для браузерів, які не підтримують addEventListener. і removeEventListener, ми скористаємося полілфілом EventListener Джонатана Нілу (Jonathan Neal).

В обох демо-прикладах ми додамо до кнопки оператор події. Клацання по кнопці та/або наведення на неї миші запустить відкриття/закриття навігації. Крім того, в першому демо при клацанні де завгодно поза відкритої навігації та закриється. Давайте почнемо з JavaScript’а першого прикладу.

(function(){
var button = document.getElementById(‘cn-button’),
wrapper = document.getElementById(‘cn-wrapper’),
overlay = document.getElementById(‘cn-overlay’);
// відкрийте і закрийте меню при клацанні по кнопці
var open = false;
button.addEventListener. (‘click’, handler, false);
button.addEventListener. (‘focus’, handler, false);
wrapper.addEventListener. (‘click’, cnhandle, false);
function cnhandle(e){
e.stopPropagation();
}
function handler(e){
if (!e) var e = window.event;
e.stopPropagation();//щоб подію клацання не запускалося в документі
if(!open){
openNav();
}
else{
closeNav();
}
}
function openNav(){
open = true;
button.innerHTML = «-«;
classie.add(overlay, ‘on-overlay’);
classie.add(wrapper, ‘opened-nav’);
}
function closeNav(){
open = false;
button.innerHTML = «+»;
classie.remove(overlay, ‘on-overlay’);
classie.remove(wrapper, ‘opened-nav’);
}
document.addEventListener. (‘click’, closeNav);
})();

JavaScript для другого демо-приклад схожий на попередній, але для даного випадку ми його модифікуємо:

(function(){
var button = document.getElementById(‘cn-button’),
wrapper = document.getElementById(‘cn-wrapper’);
//відкрийте і закрийте меню при клацанні по кнопці
var open = false;
button.addEventListener. (‘click’, handler, false);
button.addEventListener. (‘focus’, handler, false);
function handler(){
if(!open){
this.innerHTML = «Close»;
classie.add(wrapper, ‘opened-nav’);
}
else{
this.innerHTML = «Menu»;
classie.remove(wrapper, ‘opened-nav’);
}
open = !open;
}
function closeWrapper(){
classie.remove(wrapper, ‘opened-nav’);
}
})();

От і все! Сподіваюся, вам сподобався і виявився корисним цей підручник!