Повёр­ну­тый текст

Неко­то­рое вре­мя на­зад я уже де­лил­ся этим ре­ше­ни­ем в твит­те­ре, но на этот раз хочу на­пи­сать о нём немно­го по­дробнее.

За­да­ча: по­лу­чить по­вёр­ну­тый на 90 гра­ду­сов текст.

Про­бле­ма: ши­ро­ко из­вест­но, что при ис­поль­зо­ва­нии trans­form, блок ве­дёт себя ана­ло­гич­но сдви­гу че­рез po­si­tion:rel­a­tive —про­дол­жа­ет за­ни­мать ме­сто в по­то­ке по со­сто­я­нию до транс­фор­ма­ции, так что, по фак­ту, из­ме­не­ние про­ис­хо­дит толь­ко ви­зу­альное.

Од­на­ко, до­воль­но ча­сто мож­но за­хо­теть по­вер­нуть блок так, что­бы этот по­во­рот вли­ял и на по­ток. На­при­мер, если мы за­хо­тим вы­стро­ить несколь­ко вер­ти­каль­ных бло­ков в ряд, по­доб­но кни­гам на пол­ке, или если мы за­хо­тим ис­поль­зо­вать по­вёр­ну­тый текст в ка­че­стве за­го­лов­ков таб­ли­цы —в этих слу­ча­ях нам нуж­но бу­дет га­ран­ти­ро­вать, что вы­со­та ста­нет рав­на ши­рине бло­ка, в то вре­мя как ши­ри­на —вы­соте.

У меня по­лу­чи­лось ре­шить эту за­да­чу с од­ним до­пу­ще­ни­ем: нуж­но знать вы­со­ту по­во­ра­чи­ва­е­мо­го эле­мен­та. В этом слу­чае ре­а­ли­за­ция ста­но­вит­ся очень простой:

  1. Нам по­на­до­бит­ся до­пол­ни­тель­ный эле­мент. HTML каж­до­го бло­ка бу­дет при­мер­но таким:

     <span class="ro­tated-text">
         <span class="ro­tated-tex­t__in­ner">
             Ro­tated foo
         </​​span>
     </​​span>
    
  2. Врап­пе­ру мы за­да­ём вот та­кие сти­ли:

     .ro­tated-text {
         dis­play: in­line-block;
         over­flow: hid­den;
    
         width: 1.5em;
         line-height: 1.5;
     }
    

    Здесь мы де­ла­ем эле­мент ин­лайн-блоч­ным (это не кри­тич­но, сра­бо­та­ло бы и блоч­ное отоб­ра­же­ние, но ин­лайн-блок чаще бы­ва­ет ну­жен), за­тем об­ре­за­ем все вы­сту­па­ю­щие ча­сти (при­го­дит­ся поз­же), да­лее за­да­ём ши­ри­ну, рав­ную те­ку­щей вы­со­те бло­ка, —то са­мое до­пу­ще­ние (line-height тут при­ве­дён в ка­че­стве при­ме­ра того, что сей­час опре­де­ля­ет вы­со­ту бло­ка, а так как все эле­мен­ты, ис­поль­зу­е­мые в при­ме­ре, од­но­строч­ные, то это и бу­дет его вы­со­той).

  3. Внут­рен­ний эле­мент де­ла­ем ин­лайн-блоч­ным, что­бы его ши­ри­на схлоп­ну­лась по кон­тен­ту. По­сле чего за­да­ём white-space:nowrap для того, что­бы ни­че­го ни­ку­да не пе­ре­но­си­лось (ведь выше мы огра­ни­чи­ли ши­ри­ну), ну и по­во­ра­чи­ва­ем блок, счи­тая верх­ний ле­вый угол точ­кой от­счё­та (для чи­та­е­мо­сти свой­ства при­ве­де­ны без пре­фик­сов):

     .ro­tated-tex­t__in­ner {
         dis­play: in­line-block;
         white-space: nowrap;
    
         trans­form: trans­late(0,100%) ro­tate(-90deg);
         trans­form-ori­gin: 0 0;
     }
    
  4. А те­перь са­мое глав­ное: нам нуж­но сде­лать этот внут­рен­ний эле­мент «квад­рат­ным» —это сде­ла­ет вы­со­ту ко­неч­но­го эле­мен­та рав­ной ши­рине, ну а ши­ри­на у нас об­ре­за­ет­ся врап­пе­ром. Для того, что­бы сде­лать наш эле­мент квад­рат­ным, я при­ме­няю вот та­кой вот трюк:

     .ro­tated-tex­t__in­ner:af­ter {
         con­tent: "";
         float: left;
         mar­gin-top: 100%;
     }
    

    Вро­де всё до­воль­но про­сто, но немно­гие зна­ют о том, что вер­ти­каль­ные ма­джи­ны и пад­дин­ги, за­дан­ные в про­цен­тах, ис­чис­ля­ют­ся не от вы­со­ты бло­ка, а от его ши­ри­ны. Это по­ве­де­ние ред­ко ис­поль­зу­ет­ся на прак­ти­ке, но у нас как раз тот слу­чай, ко­гда оно при­го­дилось.

В ито­ге мы по­лу­ча­ем квад­рат­ный эле­мент, об­ре­за­е­мый врап­пе­ром до ши­ри­ны сво­ей про­шлой вы­со­ты, та­кой эле­мент мож­но ис­поль­зо­вать в лю­бом кон­тек­сте, для него бу­дут ра­бо­тать раз­ные свой­ства вро­де text-align или ver­ti­cal-align, так что мож­но ска­зать, мы по­лу­чи­ли «чест­ный» по­вёр­ну­тый блок.

Ну и несколь­ко жи­вых при­меров:

Заго­лов­ки таблиц

Оче­вид­ный при­мер —ком­пакт­ные по ши­рине за­го­лов­ки таблиц.

First th Some cell And another
Second th 12 12314
Third th 12 12314
First th The Second th Third th
2 4 42
12 4 234
13 100 0

«Книж­ная пол­ка»

Так как по­вёр­ну­тые бло­ки по­лу­ча­ют­ся «чест­ны­ми», то, если вы­стро­ить их в ряд, вы­со­та ряда бу­дет рав­на вы­со­те са­мо­го боль­ше­го из них:

Как-то так.

Ещё раз: мы долж­ны знать вы­со­ту бло­ка, так что, если по­на­до­бит­ся по­во­ра­чи­вать та­ким об­ра­зом мно­го­строч­ные бло­ки, нуж­но бу­дет со­от­вет­ству­ю­щим об­ра­зом из­ме­нять ши­ри­ну их врап­перов.

Кро­ме того, воз­мож­но, этот ме­тод мож­но за­ста­вить ра­бо­тать и в IE —при­ме­нив мат­рич­ный фильтр для по­во­ро­та и до­ба­вив эле­мент в за­ме­ну псев­до­эле­мен­ту. Мне лень всё это де­лать, но если кто-то это сде­ла­ет, я буду рад пулл-рек­ве­стам к этим при­ме­рам :)