Яндекс.Метрика

Дизайн-журнал №1. Актуальная информация для дизайнеров, веб дизайнеров, программистов и разработчиков сайтов.

Создаем адаптивный css-таймлайн c 3d эффектом

29 мая 2013 | Опубликовано в css | 4 Комментариев »

 В этом уроке будем экспериментировать с перспективой и, используя input  - «radio», создавать таймлайн структуру, используя чистый CSS. Идея будет заключаться в том, что при нажатии на соответствующем пункте «radio», контент будет немного расширятся и преобразовываться в 3D-подобную структуру. Мы будем использовать 3D-трансформации и переходы, а также сестринские селекторы.  

Демо                                     Скачать исходные файлы 

Пожалуйста, обратите внимание, что эффект будет нормально отображаться только в тех браузерах, которые поддерживают определенные свойства CSS.

Также нужно отметить, что 3D-эффект будет лучше всего смотреться в браузерах WebKit. 

Давайте начнем!

РАЗМЕТКА

Давайте создадим неупорядоченный список с классом “timeline”. В него добавим несколько элементов с классом “event”. Каждый event будет иметь input type="radio", пустой тег <label>, превьюшку и контейнер для контента. Этот контейнер будет иметь свойство перспективы, поэтому зададим для него класс “content-perspective”. Обратите внимание, что все формы  input имеют одинаковые названия. Этим мы определили, что они принадлежат к одной группе и за один раз мы можем выбрать только один пункт.

 

<ul class="timeline">

    <li class="event">
        <input type="radio" name="tl-group" checked/>
        <label></label>
        <div class="thumb user-4"><span>19 Nov</span></div>
        <div class="content-perspective">
            <div class="content">
                <div class="content-inner">
                    <h3>I find your lack of faith disturbing</h3>
                    <p>Some text</p>
                </div>
            </div>
        </div>
    </li>

    <li class="event">
        <input type="radio" name="tl-group"/>
        <!-- ... -->
    </li>

    <!-- ... -->
</ul>

Превью будет иметь класс “thumb” и и дополнительный класс для пользователя. span будет использоваться для добавления даты.

CSS

Обратите внимание, что CSS не будет содержать никаких префиксов, но вы сможете найти их в исходных файлах.
Мы будем использовать border-box: box-sizing и сбросим все оступы.  

*,
*:after,
*:before {
    box-sizing: border-box;
    padding: 0;
    margin: 0;
}

Конечно, Вы можете не обнулять значения полей и отступов, но это нужно учитывать при дальнейшей настройке стилей.

Давайте сначала добавить шрифт, который мы создали с помощью fontello.com . Этот шрифт будет иметь только четыре символа — две стрелки и две формы, которые мы связываем с “checked” и “unchecked”. 

 

@font-face {
    font-family: 'fontawesome-selected';
    src: url("font/fontawesome-selected.eot");
    src:
    url("font/fontawesome-selected.eot?#iefix") format('embedded-opentype'),
    url("font/fontawesome-selected.woff") format('woff'),
    url("font/fontawesome-selected.ttf") format('truetype'),
    url("font/fontawesome-selected.svg#fontawesome-selected") format('svg');
    font-weight: normal;
    font-style: normal;
}

Давайте .timeline определим как относительный и добавим к нему некоторые дополнения:

.timeline {
    position: relative;
    padding: 30px 0 50px 0;
    font-family: 'Gorditas', Arial, sans-serif;
}

Белая линия будет создана с помощью псевдо элемента. Положение будет абсолютным, также мы определим для него полосатый фон (сделанный с помощью Patternify ):

.timeline:before {
    content: '';
    position: absolute;
    width: 5px;
    height: 100%;
    top: 0;
    left: 165px;
    background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAJUlEQVQIW2NkQAP/gYARWQwkAOLDBeECjEAAkkEWAKtEFwAJAgAZEBP+oM1IkwAAAABJRU5ErkJggg==);
}
Каждый класс  event будет иметь свойство position: relative и внешний отступ от нижней границы . Это позволит убедиться, что элемент списка не будет переполнен и все будет правильно отображаться при применении 3d вращения. 

.event{

    position: relative;
    margin-bottom: 80px;
    padding-right: 40px;
}

Давайте сейчас уделим внимание левой стороне. Мы хотим создать превьюшки. Давайте зададим свойство  position: absolute. Также мы хотим сделать превьюшки круглыми. Поэтому устанавливаем радиус —  50%. 

.thumb{

    position: absolute;
    width: 100px;
    height: 100px;
    box-shadow:
        0 0 0 8px rgba(65,131,142,1),
        0 1px 1px rgba(255,255,255,0.5);
    background-repeat: no-repeat;
    border-radius: 50%;
    transform: scale(0.8) translateX(24px);
}

Также добавляем преобразования. Цель — масштабировать их при клике. Поскольку перемещать элемент нужно немного, можно сделать это путем трансформации определенно точки отсчета  transform origin или относительно оси абсцисс. Пойдем по второму пути и сместим элемент на 24 пикселя. 

 

.thumb:before {
    content: '';
    position: absolute;
    height: 8px;
    z-index: -1;
    background: transparent url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAICAYAAADA+m62AAAAPElEQVQYV2NkQAP/gYARCNDFUQRgirAphitEl0TngxXisg5ZnBGXIpgbYfIYjkb3BNxGbBLYxIgyEaQRAA8KKAWYsZtjAAAAAElFTkSuQmCC);
    width: 51px;
    top: 42px;
    left: 100%;
    margin-left: 8px;
}
Давайте определим стили для span даты. Мы определим для него position: absolute и разместим  под превью. 
.thumb span {
    color: #41838e;
    width: 100%;
    text-align: center;
    font-weight: 700;
    font-size: 15px;
    text-transform: uppercase;
    position: absolute;
    bottom: -30px;
}

Теперь, давайте определим различные фоновые изображения:

.user-1 {
    background-image: url(../images/chewbacca.jpg);
}

.user-2 {
    background-image: url(../images/barf.jpg);
}

.user-3 {
    background-image: url(../images/darkhelmet.jpg);
}

.user-4 {
    background-image: url(../images/darthvader.jpg);
}

.user-5 {
    background-image: url(../images/leia.jpg);
}

.user-6 {
    background-image: url(../images/vespa.jpg);
}

.user-7 {
    background-image: url(../images/c3po.jpg);
}
.user-8 {
    background-image: url(../images/dotmatrix.jpg);
}

Для radio input будем использовать маленькую хитрость. Мы хотим, чтобы наши переходы применялись при клике, можем использовать «checked» и сестринские селекторы. Существует много различных способов, чтобы осуществить это. Один из них -нажатие на  label, который большинство браузеров осуществляется автоматически при клике на  input. В этом случае мы будем размещать  input поверх label и делать его прозрачным. Нам кажется, что нажимать мы будем на label, но на самом деле нажатие будет происходить на форме  input. 

Итак, давайте  label  и  input разместим в одном и том же месте и зададим для них одинаковую ширину и высоту. 

.event label,

.event input[type="radio"] {
    width: 24px;
    height: 24px;
    left: 158px;
    top: 36px;
    position: absolute;
    display: block;
}

Поскольку форма input  должна стоять перед другими элементами (помните, что мы будем использовать сестринские элементы),определим для него более высокий Z-Index. Если бы мы этого не сделали, класс label находился бы сверху. 

.event input[type="radio"]{

    opacity: 0;
    z-index: 10;
    cursor: pointer;
}

Теперь давайте создадим псевдо-элемент для  label, которые будет содержать  шрифты-иконки, которые были включены раньше. 

.event label:after {
    font-family: 'fontawesome-selected';
    content: '\e702';
    background: #fff;
    border-radius: 50%;
    color: #41838E;
    font-size: 26px;
    height: 100%;
    width: 100%;
    left: -2px;
    top: -3px;
    line-height: 24px;
    position: absolute;
    text-align: center;
}

Давайте перейдем к правой стороне нашего таймлайна. Нам нужна обертка с заданным свойством perspective и левым полем. 

.content-perspective {
    margin-left: 230px;
    position: relative;
    perspective: 600px;
}

 

Для связи нашего текста с превьюшками и формой input мы будем использовать псевдо элемент, который будет выглядеть как линия:

.content-perspective:before {
    content: '';
    width: 37px;
    left: -51px;
    top: 45px;
    position: absolute;
    height: 1px;
    z-index: -1;
    background: #fff;
}

Конетнт  будет поворачиваться на 10 градусов.  

.content {
    transform: rotateY(10deg);
    transform-origin: 0 0;
    transform-style: preserve-3d;
}

Внутренний контент будет иметь фон и тень.  Это нам нужно для избежания каких-либо дефектов при отображении. 

.content-inner {
    position: relative;
    padding: 20px;
    color: #333;
    border-left: 5px solid #41838e;
    box-shadow: 0 4px 6px rgba(0,0,0,0.1);
    background: #fff;
}

Давайте зададим стили для заголовка: 

.content-inner h3 {
    font-size: 26px;
    padding: 5px 0 5px 0;
    color: #41838e;
}
Сейчас очень важная часть нашего урока. По скольку мы не можем анимировать  height: auto (это было бы оптимально, так как мы не знаем высоту элемента), будем использовать  smart hack (Lea Verou). Вместо этого будем анимировать значение max-height. Нужно заметить, что это обеспечит нормальный переход в том случае, если max-height будет приближенное к реальной высоте элемента. Нам нужно отрегулировать высоту, чтобы она не была слишком большой. Это не очень хорошее решение, особенно при адаптивном дизайне. Но в нашем эксперименте мы не хотим использовать JavaScript, поэтому в данном случае это — оптимальный вариант. 

Итак, мы установили максимальную высоту на 0 пикселей и  определили прозрачный цвет (при экспериментах с настройками можно проследить некоторые мерцания):

.content-inner p {
    font-size: 1.8px;
    max-height: 0px;
    overflow: hidden;
    color: rgba(0,0,0,0);
    text-align: left;
}

Давайте добавим небольшую стрелку в левой части, используя шрифт-иконки:

.content-inner:before {
    font-family: 'fontawesome-selected';
    content: '\25c2';
    font-weight: normal;
    font-size: 54px;
    line-height: 54px;
    position: absolute;
    width: 30px;
    height: 30px;
    color: #41838e;
    left: -22px;
    top: 19px;
    z-index: -1;
}

 

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

 

.thumb,
.thumb span,
.content-inner h3 {
    transition: all 0.6s ease-in-out 0.2s;
}

 

Внутренний контент требует перехода для теней:

.content-inner {
    transition: box-shadow 0.8s linear 0.2s;
}

Для трансформации:

.content {
    transition: transform 0.8s cubic-bezier(.59,1.45,.69,.98) 0.2s;
}

Теперь для максимальной высоты и для цвета.

.content-inner p {
    transition: max-height 0.5s linear, color 0.3s linear;
}

Теперь определяем, что будет происходить при клике на input. Как  radio - “checked”, зададим другую иконку для псевдо-класса и  изменим его цвет и тень. 

.event input[type="radio"]:checked + label:after {
    content: '\2714';
    color: #F26328;
    box-shadow: 0 0 0 5px rgba(255, 255, 255, 0.8);
}

Давайте также изменить цвет линии и заголовок контента:

.event input[type="radio"]:checked ~ .content-perspective:before {
    background: #F26328;
}
.event input[type="radio"]:checked ~ .content-perspective .content-inner h3 {
    color: #F26328;
}

 

Контент будет вращаться:

.event input[type="radio"]:checked ~ .content-perspective .content {
    transform: rotateY(-5deg);
}

Для внутреннего текста будет определен другой цвет рамки и тени.

 

.event input[type="radio"]:checked ~ .content-perspective .content-inner {
    border-color: #F26328;
    box-shadow: 10px 0px 10px -6px rgba(0, 0, 0, 0.1);
}

Стили для абзаца:

.event input[type="radio"]:checked ~ .content-perspective .content-inner p {
    max-height: 260px; /* Add media queries */
    color: rgba(0,0,0,0.6);
    transition-delay: 0s, 0.6s;
}

 

Установка задержки для переходов гарантирует , что цветовой переход будет происходить с задержкой. 

Сначала мы определили max-height для анимации, а затем то прозрачность RGBA цвета.

Давайте изменим цвет стрелки:

.event input[type="radio"]:checked ~ .content-perspective .content-inner:before {
    color: #F26328;
}

Превьюшка также будет расширятся: 

.event input[type="radio"]:checked ~ .thumb {
    transform: scale(1);
    box-shadow:
        0 0 0 8px rgba(242,99,40,1),
        0 1px 1px rgba(255,255,255,0.5);
}

Изменяем цвет даты:

.event input[type="radio"]:checked ~ .thumb span {
    color: #F26328;
}

Также изменим синие зигзаги на оранжевые:

.event input[type="radio"]:checked ~ .thumb:before {
    background: transparent url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAICAYAAADA+m62AAAAPUlEQVQYV2NkQAOfUjX+882+wYgujiIAU4RNMVwhuiQ6H6wQl3XI4oy4FMHcCJPHcDS6J2A2EqUQpJhohQBbNyaHFmzEqgAAAABJRU5ErkJggg==);
}

Теперь нужно убедиться, что все будет хорошо выглядеть при уменьшении размеров экрана.  Для 850 пикселей  установим меньший размер шрифта, а также скинем max-height  для абзаца. 

 

@media screen and (max-width: 850px) { 
    .content-inner h3 {
        font-size: 20px;
    }

    .content-inner p {
        font-size: 14px;
        text-align: justify;
    }
    .event input[type="radio"]:checked ~ .content-perspective .content-inner p {
        max-height: 500px;
    }
}

 

Для 540 px нужно сделать еще несколько вещей. Превьюшка будет оставаться на том же месте,а  основной текст будет размещаться под ней. Форма  input разместиться поверх превьюшки, так что, чтобы открыть текст, нужно будет кликнуть по картинке. Также будут удалены некоторые элементы, такие как метки и линии. 

 

@media screen and (max-width: 540px) {
    .timeline:before {
        left: 50px;
    }

    .event {
        padding-right: 0px;
        margin-bottom: 100px;
    }

    .thumb {
        transform: scale(0.8);
    }

    .event input[type="radio"] {
        width: 100px;
        height: 100px;
        left: 0px;
        top: 0px;
    }

    .thumb:before,
    .event input[type="radio"]:checked ~ .thumb:before {
        background: none;
        width: 0;
    }

    .event label {
        display: none;
    }

    .content-perspective {
        margin-left: 0px;
        top: 80px;
    }

    .content-perspective:before {
        height: 0px;
    }

    .content {
        transform: rotateX(-10deg);
    }

    .event input[type="radio"]:checked ~ .content-perspective .content {
        transform: rotateX(10deg);
    }

    .content-inner {
        border-left: none;
        border-top: 5px solid #41838e;
    }

    .event input[type="radio"]:checked ~ .content-perspective .content-inner {
        border-color: #F26328;
        box-shadow: 0 10px 10px -6px rgba(0, 0, 0, 0.1);
    }

    .content-inner:before {
        content: '\25b4';
        left: 33px;
        top: -32px;
    }
    .event input[type="radio"]:checked ~ .content-perspective .content-inner p {
        max-height: 300px;
    }
}

 

Значение max-height   нужно будет отредактировать еще раз. 

Если вы хотите, чтобы был возможен выбор нескольких элементов, для формы input используйте вместо radio тип «checkbox».

Надеемся, вам понравился этот урок!

Демо                                     Скачать исходные файлы 

Автор урока: Mary Lou

Перевод — Дежурка

Смотрите также:




Комментарии

  1. Константин
    Thumb up Thumb down +4

    Ну блин ни фига себе как круто. СПАСИБО УОТ ТАКОЕ!!!!

  2. Константин
    Thumb up Thumb down 0

    Не выдержал, ещё раз напишу, спасибо, очень-очень вовремя!!!

    marina Ответ:

    Thumb up Thumb down 0

    =)))

[an error occurred while processing the directive]


[an error occurred while processing the directive]