Como escrever um livro viável usando regiões CSS e transformações 3D

Ilmari Heikkinen

Então, o dia chegou. Você finalmente se cansou dos longos pergaminhos de texto e está procurando um novo formato. Algo elegante. Algo compacto. Algo que pega o longo pergaminho, corta-o em pequenos retângulos e os une. Eu chamo essa invenção de "livro".

Com o poder das regiões CSS (CanIUse, acesse chrome://flags e ative as regiões CSS) e as transformações 3D do CSS, a tecnologia de ponta para livros finalmente está disponível nos navegadores mais recentes. Você só precisa de algumas linhas de JavaScript e bastante CSS.

Vamos começar definindo a estrutura do nosso livro. O livro tem páginas, e elas têm dois lados. As laterais contêm o conteúdo do livro:

<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>

Vamos usar regiões CSS para enviar o texto do livro às páginas dele. Mas, primeiro, precisamos do texto do livro.

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

Agora que escrevemos nosso livro, vamos definir o fluxo de CSS. Estou usando o caractere + como marcador de posição do prefixo do fornecedor. Substitua-o por -webkit- nos navegadores WebKit, -moz- no Firefox e assim por diante:

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

Agora o conteúdo do período #book-content vai para os divs .book-pages. Contudo, este é um livro ruim. Para um livro mais literário, precisamos embarcar em uma missão. Nossa jornada levará pela ponte do arco-íris das transformações do CSS ao reino do relógio do JavaScript. Nos salões dos fanáticos mecânicos, devemos liberar magia de transição épica e obter as três chaves lendárias que controlam a interface do mundo.

O guardião da ponte arco-íris transmite a sabedoria dos seletores estruturais estilosos para que possamos transformar nossa estrutura de livro HTML em uma forma mais semelhante a um livro:

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;
}

Ao criar, assim, um estilo em forma de papel para nosso HTML, chegamos aos portões de trilhões de rodas do reino JavaScript. Para passar pelo portão, precisamos transformar nosso livro plano em um volume adequado. Para adicionar volume ao livro, deslocamos cada página ligeiramente no eixo 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)');
    }
    }
}
})();

Fazer a mágica da transição para impressionar os fadas não é uma das invocações mais difíceis. No entanto, os resultados fazem com que as páginas do nosso livro tenham uma animação suave.

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

Por fim, para fazer as páginas realmente virarem, precisamos vincular os próprios eventos à nossa causa.

(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++;
        }
    };
})();

Com isso, adquirimos a tecnologia do livro e podemos evacuar as torres de cristal do mundo todo e deixar para trás seu brilho cego e os fogos nucleares ferozes de Achenar, a grande estrela azul da união global. Nós triunfantemente voltamos para nossos lares, hasteando nossos livros bem acima da nossa cabeça, prontos para a inevitável cascata de desfiles e celebrações em nossa homenagem.

Veja um exemplo on-line aqui e acesse a fonte completa para os exemplos. Se você não tiver regiões CSS no navegador, o exemplo parecerá bastante corrompido. Nesse caso, tente este exemplo.