DEV Community

Cover image for Making Miniature Book with CSS
hashrock
hashrock

Posted on

Making Miniature Book with CSS

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

Discussion (1)

Collapse
mxldevs profile image
MxL Devs

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