CSS акордеон

Има дни, в които човек иска да поекспериментира, да прави неща по нестандартен начин, като например да си направиш сайт само с css, без нито 1 ред html, да пробваш да заредиш 1 милиард 3d обекта чрез webgl и т.н. Еми днес е един такъв ден.

Какво ще правим?
Крайният продукт днес ще бъде плъзгащ се, анимиран и цъкаем хоризонтален акордеон. Ще имаме няколко вертикални полета, които при клик се скриват и показват. До тук всичко изглежда напълно познато и постигнато от много UI библиотеки. Интересното в случая е, че ние ще го направим само с css ? .

За нетърпеливите ето демо на резултата.

п.с. плъгина ми за показване на код нещо няма ъпдейт за текущата версия на wordpress и се налага малко да се скролва, но няма как…

Кликаем CSS

Както може би сте добре запознати, CSS не поддържа цъкаеми събития (click events). И може би тук започвате да схващате, ако вече не сте – къде точно се крие предизвикателството. Как тогава ще накараме нашето съдържание да се плъзка при клик? Можем много бързо да променим началната си идея и да направим акордеона да работи при hover, но няма да е толкова забавно. Затова нека опитаме някои трикчета с група радио бутони.
С помощта на радио бутоните имаме всичко необходимо – група цъкаеми обекти, където само 1 може да бъде избран и този 1 е лесен за селектиране и стилизиране. До тук супер. Семантика? Емииии имайки предвид, че е експериментален проект за сега нека приемем, че няма да обръщаме внимание на семантиката, понеже това, което ще правим, няма да се доближава много много до семантичен html. Ако искате да постигнете подобен резултат, който да е семантичен – насочете се към js.

Стъпка 1: HTML frame

Изграждането на нов web проект е като изграждането на къща. Първо поставяме основите, върху които след това можем да сложим всичко друго, от което имаме нужда. За това нека започнем с малко html.
Първото, от което ще имаме нужда е един неподреден списък във form елемент. Това изглежда малко странно за момента, но след малко ще придобие малко повече смисъл.

<form>
  <ul>
    <li></li>
    <li></li>
    <li></li>
  </ul>  
</form> 

Тук всяка единица (li) от списъка ще представлява слайд. Ако искате 5 слайда, ще трябва просто да си добавите още 2 единици към списъка. Нашият проект в случая обаче ще ползва 3 слайда, които са напълно достатъчни, за да добием представа за желания ефект. За какво обаче ни е form елемента?
Във всяка една единица от списъка, ще поставим по 3 елемента – input, label и div. Input-ите ще бъдат радио бутони, които са свързани с label-и. Обединени, тези два елемента ще ни осигурят контрола над нашия акордеон. Div-a просто ще държи съдържанието, което искаме да имаме на текущия слайд.

<form>
  <ul>
    <li>
      <input id="rad1" type="radio" name="radio">
      <label for="rad1">1</label>
      <div class="accslide">
      </div>
    </li>
    <li>
      <input id="rad2" type="radio" name="radio">
      <label for="rad2">2</label>
      <div class="accslide">
      </div>
    </li>
    <li>
      <input id="rad3" type="radio" name="radio">
      <label for="rad3">3</label>
      <div class="accslide">
      </div>
    </li>
    </ul>  
</form>

С радио бутоните и функционалността им всичко е ок, но проблема е, че те изглеждат… ами като радио бутони… Но естествено можем да поправим това с малко css.

Стъпка 2: Пренаписване стиловете на формата

Следващото ни предизвикателство е да накараме грозните радио бутони да изглеждат по шукарени. Ето как изглежда html-a ни без никакви стилове.

img1

Както можете да видите между точките от списъка и лейбълите ни, се позиционират радио бутоните. Но едно по едно – като за начало нека си зачистим стиловете (по мързеливия начин – както вече уточнихме, за целите на проекта ще си спестим някои добри практики)

* {
  margin: 0;
  padding: 0;
  -moz-box-sizing: border-box;
  -webkit-box-sizing: border-box;
  box-sizing: border-box;
}
ul {
  list-style: none;
}
input {
  position: absolute;
  top: -9999px;
  left: -9999px;
}

Предполагам е ясно какво прави този код, но все пак – зануляваме разстояният и отстоянията на всички елементи, така че да са еднакви при всички browser-и и, че отстоянията няма да се бъркат при задаването на размерите. Постигаме това, чрез пропъртито box-sizing, което преправя стандартния box модел да бъде по – приятелски настроен.

Другото логично действие е премахването на стила на списъците, което ще махне гадните черни точици.

Накрая хващаме нашите радио бутончета и ги махаме от екрана или с други думи казано просто им слагаме абсолютна позиция и ги пращаме на тази иначе толкова ключова позиция 9999, 9999. Сигурно сте обърнали внимание, че селектора ни тук е глобален. Ако ви се наложи да реализирате подобно нещо в реален проект, може би ще ви се наложи да реализирате селектиране по някой алтернативен начин.

Стилизиране на label-ите

След като радио бутоните ни са скрити можем да сме доволни, но защо всъщност ги скрихме? Как ще контролираме акордеона след като радио бутони ни са там, където монитор не огрява. Отговора може би е очевиден за по – напредналите – label-ите ни ще служат за допълнителна цъкаема точка, просто защото могат да бъдат стилизирани по – свободно. Т.е. дори и невидим радио бутонът ни ще запази своята функционалност чрез label-ите, единственото, което трябва да направим е да ги направим да изглеждат хубави.

label {
  display: block;
  float: left;
  height: 330px;
  width: 50px;
  margin-bottom: 10px;
  overflow: hidden;


  background: #BAE4F7;
  text-align: center;
  font: 14px/50px Helvetica, Verdana, sans-serif;  
 

  -webkit-transition: width 1s ease, background 0.5s ease;
     -moz-transition: width 1s ease, background 0.5s ease;
       -o-transition: width 1s ease, background 0.5s ease;
      -ms-transition: width 1s ease, background 0.5s ease;
          transition: width 1s ease, background 0.5s ease;
}

Тук съм оставим малко разстояние между отделни части от кода, за да можем да ги обсъдим по – добре. Първото парче се грижи за пространственото поведение на нашите label-и – височина, широчина, разстояния, overflow и т.н. На практика ги превръщаме в големи правоъгълници, стоящи един до друг.
Следващата група настройки се грижи за изгледа на label-ите. Променяме фоновия цвят, центрираме текста и му даваме някакъв шрифт и размери.
Най – накрая, слагаме малко transition ефекти, за да постигнем лека анимация, за която ще стане дума след малко.

Стъпка 3: Още малко стилизиране на label-ите

С последните няколко стилизация успяхме да превърнем скучния си списък с радио бутони в нещо по – близко до това, което се опитваме да постигнем.

img2png

Въпреки това обаче, нека подобрим малко потребителския изглед, така че табовете да се различават малко по – лесно.

#rad2 + label {
  background: #A4CCDE;
  -webkit-transition: width 1s ease, background 0.5s ease;
     -moz-transition: width 1s ease, background 0.5s ease;
       -o-transition: width 1s ease, background 0.5s ease;
      -ms-transition: width 1s ease, background 0.5s ease;
          transition: width 1s ease, background 0.5s ease;
}
 
label:hover, #rad2 + label:hover {
  background: #95BBCC;
  color: #fff;
  cursor: pointer;
}

Тук затъмнихме малко вторият ни таб, така че да се отличава малко от другите два. Добавихме още един transition и hover ефект, така че всеки път, когато потребителя мине през тях, цвета им да потъмнява. И така постигаме още по добър изглед за табовете си.

img3
img4

Стъпка 4: HTML на слайдовете

След като се позанимавахме малко с css, нека се върнем на нашия недовършен html.

<form>
  <ul>
   <li>
    <input id="rad1" type="radio" name="rad">
    <label for="rad1">1</label>
    <div class="accslide">
     <h2><a href="http://pavelkolev.com/html5-snippets/">HTML5 snippets</a></h2>
     <p> Ето няколко snippet-a, които можете да използвате (надявам се, нещата да ви станат по – ясни след като ги прегледате).</p>
     <img src="http://pavelkolev.com/wp-content/uploads/2013/01/img7.png" alt="" />
    </div>
   </li>
   <li>
    <input id="rad2" type="radio" name="rad">
    <label for="rad2">2</label>
    <div class="accslide">
     <h2><a href="http://pavelkolev.com/web-design-терминология-част-1-html/">Web design терминология</a></h2>
     <p>Ако сте нов в web design-a, едно от първите неща, с които по всяка вероятност ще се сблъскате е жаргона (терминологията). Има толкова много определения за различни неща, които толкова много си приличат, че е изключително лесно човек да се обърка.</p>
     <img src="http://pavelkolev.com/wp-content/uploads/2013/01/img6.png" alt="" />
    </div>
   </li>
   <li>
    <input id="rad3" type="radio" name="rad">
    <label for="rad3">3</label>
    <div class="accslide">
     <h2><a href="http://pavelkolev.com/html-rechnik/">HTML5 snippets</a></h2>
     <p>Забравили сте някой от таговете в html? Искате да намерите точния таг, който да отговаря на това което искате да постигнете? Тук е мястото, където можете да намерите това, което търсите, заедно със допълнителни съвети, SEO съвети, както и списък със поддържаните атрибути за всеки елемент.</p>
     <img src="http://pavelkolev.com/wp-content/uploads/2013/01/img5.png" alt="" />
    </div>
   </li>
  </ul>  
 </form>        

На практика всичко, което правим, е добавянето на някакви заглавия, картинки, параграфи – стандартни неща, които могат да се появят в един акордеон.

Стъпка 5: Стилизиране на слайдовете

Почти сме готови. Това, което ни остана да направим е да стилизираме малко нашето съдържание и да показваме само съдържанието на кликнатия таб. Та по същество.
Стиловете за слайда ни много наподобяват тези за таба, които използвахме преди малко. Но ако float-нем и тях, те ще застанат до таб партниора си. Затова просто им даваме нулева широчина, за да са невидими.

.accslide {
  display: block;
  height: 330px;
  width: 0px;
  padding: 10px 0;
  float: left;
  overflow: hidden;
 
  color: #333;
  background: #fff;
  font: 12px/1.5 Helvetica, Verdana, sans-serif;
   
  -webkit-transition: all 1s ease;
     -moz-transition: all 1s ease;
       -o-transition: all 1s ease;
      -ms-transition: all 1s ease;
          transition: all 1s ease;
}
 
.accslide p, h2, img {
  width: 420px;
  padding-left: 10px;
}
 
.accslide img {
  margin-top: 10px;
}

Разширяване при селектиране

Всичките тези усилия и почти нищо не сме направили още… или поне нищо работещо. Всъщност, това което имаме до момента не прави нищо. За щастие transition-ите ни са си на място и всичко е точно стилизирано, което улеснява положението, стига да успеем да кажем на browser-a да увеличава широчината на слайда, когато лейбълът му е селектиран.
Това като цяло е най – готината част от целия експеримент. И въпреки това е страшно простичко.

input[type="radio"]:checked+label ~ .accslide {
  width: 450px;
}

Те! Това е целия css от който имаме нужда, за да направим нашия акордеон от статичен – функционален. Та какво всъщност се случва тук? Този селектор може и да изглежда сложен, но си е доста простичък. Първо input[type=’radio’] ни селектира всички радио бутони. Добавяме псевдоселектора :checked за да обхванем само слектираните радио бутони. След това селектираме свързания с радио бутона label и променяма настройките на класа. Ако селектирахме само класа обаче, това би довело до разширяване на всички слайдове едновременно.

Заключение

Свърши някак си изненадващо. Но това е всичко. Вече си имаме напълно работещ css акордеон. От тук нататък както можете да се досетите идеи бол – свързани с checkbox-ове и с radio бутони. Знам, че същото нещо може да се постигне и с target псевдоселектора, но някак си ми се губи красотата на идеята тогава. Ще се радвам на коментари какво мислите по въпроса.


5 Responses to “CSS акордеон”

  1. Ivan Pankov says:

    Много е забавно. И аз си правих такъв акордеон, исках да направя менютата на сайдбара по този начин, но после реших че не ми харесва да имам checkbox и radio елементи които в чист HTML нямат смисъл. Т.е. като махна css-а остават някакви елементи които нямат отношение към съдържанието. Иначе идеята е страхотна, и очакваме още CSS глезотии които да се поддържат от браузерите :).

  2. Jason Zhekov says:

    Това с :checked е интересен хак.
    Но мисля, че ще е по-добре ако се ползва CSS :target. Така ще се получи по-семантичен HTML и ще има възможност за линкване директно към таба от акордеона.

  3. Много готино :) И ми помогна за едно от домашните в академията. Само че там правим галерия със снимки и като кликнем на някоя от тях тя се показва в голям размер.

  4. Sirma says:

    Супер! =) Само едно дребно нещо, вместо да пращаме радиобутоните на “майната си” ; ) не е ли по-лесно да им кажем:

    input {
    display: none;
    }

    и резултатът няма ли да е същия?

Leave a Reply

Your email address will not be published. Required fields are marked *