Написание переворачивающейся книги с использованием CSS-регионов и 3D-преобразований

Ilmari Heikkinen

Так. Этот день настал. Вам наконец-то надоели длинные прокрутки текста, и вы ищете новый формат. Что-то элегантное. Что-то компактное. Что-то, что берет длинный свиток, разрезает его на аккуратные маленькие прямоугольники и связывает их вместе. Я называю это изобретение «книгой».

Благодаря возможностям регионов CSS ( CanIUse , перейдите по адресу chrome://flags и включите регионы CSS) и 3D-преобразованиям CSS, передовая книжная технология наконец-то стала доступна в современных браузерах. Все, что вам нужно, это несколько строк JavaScript и много CSS.

Давайте начнем с определения структуры нашей книги. Книга состоит из страниц, а страницы состоят из двух сторон. На боках содержится содержание книги:

<div class="book">
   
<div> <!-- first page -->
   
<div> <!-- front cover -->
        # My Fancy Book
   
</div>
   
<div> <!-- backside of cover -->
        # By Me I. Myself
        ## 2012 Bogus HTML Publishing Ltd
   
</div>
   
</div>
   
<!-- content pages -->
   
<div>
   
<!-- front side of page -->
   
<div class="book-pages"></div>
   
<!-- back side of page -->
   
<div class="book-pages"></div>
   
</div>
   
<div>
   
<div class="book-pages"></div>
   
<div class="book-pages"></div>
   
</div>
   
<div>
   
<div class="book-pages"></div>
   
<div class="book-pages"></div>
   
</div>
</div>

Мы собираемся использовать регионы CSS для размещения текста книги на страницах книги. Но сначала нам нужен текст книги.

<span id="book-content">
    blah blah blah ...
</span>

Теперь, когда мы написали нашу книгу, давайте определим CSS потока. Я использую символ + в качестве заполнителя префикса поставщика, заменяю его на -webkit- для браузеров WebKit, -moz- для Firefox и так далее:

#book-content {
   
+flow-into: book-text-flow;
}
.book-pages {
   
+flow-from: book-text-flow;
}

Теперь содержимое из диапазона #book-content будет помещено в элементы div .book-pages. Хотя это довольно слабая книга. Чтобы получить более книжную книгу, мы должны отправиться на поиски. Наше путешествие должно пройти по радужному мосту преобразований CSS в заводное царство JavaScript. В залах механистических лордов фей мы применим эпическую магию перехода и получим легендарные три ключа, управляющие интерфейсом внешнего мира.

Хранитель радужного моста передает нам мудрость стильных структурных селекторов, чтобы мы могли превратить нашу HTML-книжную структуру в более книжную форму:

html {
   
width: 100%;
   
height: 100%;
}
body
{
   
/* The entire body is clickable area. Let the visitor know that. */
   
cursor: pointer;
   
width: 100%;
   
height: 100%;
   
/* Set the perspective transform for the page so that our book looks 3D. */
   
+perspective: 800px;
   
/* Use 3D for body, the book itself and the page containers. */
   
+transform-style: preserve-3d;
}
.book {
   
+transform-style: preserve-3d;
   
position: absolute;
}
/* Page containers, contain the two sides of the page as children. */
.book > div {
   
+transform-style: preserve-3d;
   
position: absolute;
}
/* Both sides of a page. These are flat inside the page container, so no preserve-3d. */
.book > div > div {
   
/* Fake some lighting with a gradient. */
   
background: +linear-gradient(-45deg, #ffffff 0%, #e5e5e5 100%);
   
width: 600px;
   
height: 400px;
   
overflow: hidden;
   
/* Pad the page text a bit. */
   
padding: 30px;
   
padding-bottom: 80px;
}
/* Front of a page */
.book > div > div:first-child {
   
/* The front side of a page should be slightly above the back of the page. */
   
+transform: translate3d(0px, 0px, 0.02px);
   
/* Add some extra padding for the gutter. */
   
padding-left: 40px;
   
/* Stylish border in the gutter for visual effect. */
   
border-left: 2px solid #000;
}
/* Back of a page */
.book > div > div:last-child {
   
/* The back side of a page is flipped. */
   
+transform: rotateY(180deg);
   
padding-right: 40px;
   
border-right: 2px solid #000;
}
/* Front cover of the book */
.book > div:first-child > div:first-child {
   
/* The covers have a different color. */
   
background: +linear-gradient(-45deg, #8c9ccc 0%, #080f40 100%);
   
/* Put a border around the cover to make it cover the pages. */
   
border: 2px solid #000;
   
/* And center the cover. */
   
margin-left: -1px;
   
margin-top: -1px;
}
/* Back cover of the book */
.book > div:last-child > div:last-child {
   
background: +linear-gradient(-45deg, #8c9ccc 0%, #080f40 100%);
   
border: 2px solid #000;
   
margin-left: -1px;
   
margin-top: -1px;
}

Создавая таким образом стиль нашего HTML, напоминающий бумагу, мы приближаемся к триллионам ворот царства JavaScript. Чтобы пройти через ворота, нам нужно превратить нашу плоскую книгу в полноценный том. Чтобы добавить книге объема, мы слегка смещаем каждую страницу по оси Z.

(function() {
var books = document.querySelectorAll('.book');
for (var i = 0; i < books.length; i++) {
   
var book = books[i];
   
var pages = book.childNodes;
   
for (var j = 0; j < pages.length; j++) {
   
if (pages[j].tagName == "DIV") {
        setTransform
(pages[j], 'translate3d(0px, 0px, ' + (-j) + 'px)');
   
}
   
}
}
})();

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

.book > div {
   
+transition: 1s ease-in-out;
}

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

(function(){
   
// Get all the pages.
   
var pages = document.querySelectorAll('.book > div');
   
var currentPage = 0;
   
// Go to previous page when clicking on left side of window.
   
// Go to the next page when clicking on the right side.
    window
.onclick = function(ev) {
       
if (ev.clientX < window.innerWidth/2) {
        previousPage
();
       
} else {
        nextPage
();
       
}
        ev
.preventDefault();
   
};
   
var previousPage = function() {
       
if (currentPage > 0) {
        currentPage
--;
           
// Rotate the page to closed position and move it to its place in the closed page stack.
        setTransform
(pages[currentPage], 'translate3d(0px,0px,' + (-currentPage) + 'px) rotateY(0deg)');
       
}
   
};
   
var nextPage = function() {
       
if (currentPage < pages.length) {
           
// Rotate the page to open position and move it to its place in the opened stack.
        setTransform
(pages[currentPage], 'translate3d(0px,0px,' + currentPage + 'px) rotateY(-150deg)');
        currentPage
++;
       
}
   
};
})();

Благодаря этому мы приобрели «книжную» технологию и можем эвакуировать хрустальные башни надземного мира, оставив после себя их ослепляющий свет и яростные ядерные пожары Ахенара, великой голубой звезды, соединяющей верхний мир. Мы с триумфом возвращаемся в свои дома, высоко над головами размахивая книгами, готовые к неизбежному каскаду парадов и празднований в нашу честь.

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