loading...
Cover image for Making Miniature Book with CSS

Making Miniature Book with CSS

hashrock profile image hashrock ・2 min read

Alt Text

As a front-end exercise, I've made a habit of making UI components every Friday.

You can see some of the components I've made in the past in the tag #金曜GUI.

I like small, cute things like miniatures, and yesterday I made a Miniature Book component with CSS and Vue.js.

1. Place some divs at absolute

Alt Text

2. Adding a three-dimensional page with perspective properties

Alt Text

To rotate the div in 3D, use the perspective and transform-style properties.

wrapper:

  perspective: 300px;
  transform-style: preserve-3d;

item:

  transform-origin: left center;
  transform: rotateY(30deg);

You can use transform-origin and position: absolute to adjust the position.

Alt Text

3. Curve the edges of the page

Alt Text

CSS can be used to create joint animations. I learned this from s14garnet.

Alt Text

Transformations are affected by the parent element. they can be concatenated using preserve-3d.

4. Add dragging interactions to continuously turn pages

Alt Text

The implementation of drag interaction is straightforward: just keep track of the difference in offsetX and reflect it in the rotation angle.

You can use modulo to loop the book, but note that JavaScript modulo can return a negative value.

HTML:

<div id="app"
       @pointerdown="down"
       @pointermove="move"
       @pointerup="up">
  ...
</div>

JavaScript:

Number.prototype.mod = function (n) {
  return ((this % n) + n) % n;
};
new Vue({
  el: "#app",
  data: {
    rotateRaw: 40,
    rotateOld: 0,
    offset: null
  },
  methods: {
    down(ev) {
      this.$el.setPointerCapture(ev.pointerId);
      this.offset = ev.offsetX;
      this.rotateOld = this.rotate;
    },
    up(ev) {
      this.offset = null;
    },
    move(ev) {
      if (this.offset) {
        this.rotateRaw = this.rotateOld - (ev.offsetX - this.offset);
      }
    }
  },
  computed: {
    rotate() {
      return this.rotateRaw.mod(180);
    }
  }
});

Note that the pointerdown, pointermove and pointerup events require a polyfill in iOS Safari.

To prevent the div element in the wrapper from being selected by dragging, use pointer-events: none to make the Pointer events transparent.

.wrapper {
  ...
  pointer-events: none;
  user-select: none;
}

Here's DEMO:

https://codepen.io/hashrock/pen/RwrxeKe

Vue.js and input type="range" are your friends

I like to adjust the look and feel of the UI with input type="range". It's a one off UI editor. It's similar to building scaffolding to build a house.

Alt Text

Alt Text

Alt Text

input type="range" is useful, but don't forget to write v-model.number to convert its value to a number.

<input type="range" min=0 max=180 step=1 v-model.number="rotate">

Posted on by:

hashrock profile

hashrock

@hashrock

A programmer and illustrator working in Tokyo. I'm typical otaku and love mangas and animations. I want English speaker friends, feel free to add me on twitter.

Discussion

markdown guide
 

Cute components! I'm impressed how relatively little code and is required to implement and even customize it