Tips for positioning multiple cubes next to each other with the correct perspective using CSS transforms

Currently, I have a project setup in Code Sandbox:

https://codesandbox.io/s/zno5rk648p?module=%2Fsrc%2Fcomponents%2FCube.vue

A snapshot is provided below (please note that the appearance of cubes may vary if you change the viewport size):

https://i.sstatic.net/choNg.png

Purpose:

The objective is to arrange cubes next to each other or on top of each other, maintaining stacking as if filling up the back of a truck: Begin at the rear of the truck, fill the first layer with boxes, then stack on top until reaching the ceiling; continue stacking in front of those boxes until the truck is fully loaded.

Additionally, when scaling the screen, the positions of the cubes should still appear adjacent to one another (unlike the current example).

We can utilize Vue or JavaScript for calculations beyond CSS capabilities, but the emphasis is to utilize CSS extensively.

Data Overview:

The markup structure is as follows:

<div class="container">
  <div class="cubes-container">
    <!-- for each cube --->
    <div class="cube-wrap" >
        <div class="cube depth cube-isometric">
          <div class="front-pane">cube 1</div>
          <div class="back-pane">back 1</div>
          <div class="top-pane">top 1</div>
          <div class="bottom-pane">bottom 1</div>
          <div class="left-pane">left 1</div>
          <div class="right-pane">right 1</div>
        </div>
    </div>
  </div>
</div>

Positioning the cube on the right side of the first cube was not ideal, as it only works at specific resolutions:

.cube-wrap:nth-child(2) .cube {
    transform: translate3d(142.5px, 50px, 125px) rotateX(-30deg) rotateY(-45deg);
    transform-style: preserve-3d;
}

The controls on the left were also suboptimal. They modified the left and top values of .cube-wrap. By inputting numbers, you can observe the movement of cubes. Moreover, adding an extra cube reveals how the third one aligns with the "origin." These controls were initially intended for positioning cube testing purposes.

An attempt was made by setting the perspective on the container to view all cubes from a distinct vantage point:

.container {
  position: absolute;
  left: 240px;
  top: 0;
  bottom: 0;
  right: 0;
  background: grey;
  perspective: 1000px;
  perspective-origin: 50% 100px;
}

The CSS styling for the cube (omitting additional browser-specific extensions for brevity) was adopted from https://davidwalsh.name/css-cube

.cube-isometric {
  transform: rotateX(-30deg) rotateY(-45deg);
  transform-origin: 50% 50% 0;
}
/*************** STANDARD CUBE ***************/

.cube {
  position: relative;
  width: 200px;
  margin: 0 auto;
  transform-style: preserve-3d;
  animation: cube-spin 5s infinite linear;
}
.cube div {
  position: absolute;
  width: 200px;
  height: 200px;
  background: rgba(38, 93, 79, 0.87);
  box-shadow: inset 0 0 30px #c7ffb6;
  font-size: 20px;
  text-align: center;
  line-height: 200px;
  color: rgb(255, 255, 255);
  font-family: sans-serif;
  text-transform: uppercase;
}
.depth div.back-pane {
  transform: translateZ(-100px) rotateY(180deg);
}
.depth div.right-pane {
  transform: rotateY(-270deg) translateX(100px);
  transform-origin: top right;
}
.depth div.left-pane {
  transform: rotateY(270deg) translateX(-100px);
  transform-origin: center left;
}
.depth div.top-pane {
  transform: rotateX(-90deg) translateY(-100px);
  transform-origin: top center;
}
.depth div.bottom-pane {
  transform: rotateX(90deg) translateY(100px);
  transform-origin: bottom center;
}
.depth div.front-pane {
  transform: translateZ(100px);
}

I'm seeking guidance on correcting the perspective to ensure proper behavior. The challenge lies in understanding the exact placement within 2D space to achieve the desired 3D illusion, along with identifying the appropriate rotation and perspective combination for generating this effect.

Answer №1

Start by constructing the cubes from a single face and then build the other faces in the same position as the base, but rotate or translate them accordingly.

These cubes can be arranged in 2D space using flex or any other method that works best for you.

Feel free to give the container the orientation of your choice.

Hover over the container to fold the faces and get a better understanding of the basic layout

div {
    transform-style: preserve-3d;
    transition: transform 5s;
}

.container:hover .cubebase div {
    transform: rotate(0deg);
}
.container:hover .cubebase .cover {
    transform: transformZ(0px);
}


.cubebase {
    width: 100px;
    height: 100px;
    position: relative;
    background-color: rgba(255,0,0, 0.1);
    box-shadow: inset 0px 0px 5px red;
}
.cubebase:nth-child(2) {
    background-color: rgba(0,255,0, 0.2);
    box-shadow: inset 0px 0px 5px green;
}
.cubebase:nth-child(3) {
    background-color: rgba(0,0,255, 0.2);
    box-shadow: inset 0px 0px 5px blue;
}
.cubebase:nth-child(4) {
    background-color: rgba(200,200,0, 0.3);
    box-shadow: inset 0px 0px 5px brown;
}

.cubebase div {
   width: 100px;
   height: 100px;
   position: absolute;
   background-color: inherit;
   box-shadow: inherit;
   top: 0px;
   left: 0px;
}

div.rface {
    transform: rotateY(90deg);
    transform-origin: right;
}

.lface {
    transform: rotateY(-90deg);
    transform-origin: left;
}

.tface {
    transform: rotateX(90deg);
    transform-origin: top;
}
.bface {
    transform: rotateX(-90deg);
    transform-origin: bottom;
}

.cover {
    transform: translateZ(100px);
}


.container {
    border: solid 1px silver;
    transform: rotateY(20deg) rotateX(190deg);
    perspective: 5000px;
    top: 50px;
    left: 50px;
    position: relative;
    width: 300px;
    display: flex;
    flex-wrap: wrap;
}
<div class="container">
    <div class="cubebase">
        <div class="rface"></div>
        <div class="lface"></div>
        <div class="tface"></div>
        <div class="bface"></div>
        <div class="cover"></div>
    </div>
    <div class="cubebase">
        <div class="rface"></div>
        <div class="lface"></div>
        <div class="tface"></div>
        <div class="bface"></div>
        <div class="cover"></div>
    </div>
    <div class="cubebase">
        <div class="rface"></div>
        <div class="lface"></div>
        <div class="tface"></div>
        <div class="bface"></div>
        <div class="cover"></div>
    </div>
    <div class="cubebase">
        <div class="rface"></div>
        <div class="lface"></div>
        <div class="tface"></div>
        <div class="bface"></div>
        <div class="cover"></div>
    </div>
</div>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Insert information into a dialog box in Vuetify

I am currently exploring Vuetify and working on creating a user interface that displays a table of discovered Wifi networks along with each network's properties. Users should have the ability to edit the stored password or remove a Wifi network from t ...

How can values be populated from an input box in the background in Vue.js?

I'm working on a project that involves Vue.js and Quasar. One of the requirements is an input field initialized with 10 zeros, only allowing numeric numbers. The catch is that when adding a number, it should fill in from behind. "0000000000" -> a ...

Changing the appearance of your website on various pages using WordPress: activating unique stylesheets

When connecting my stylesheets to my WordPress theme, I include the following in my customtheme/style.css file: @import url('bootstrap/bootstrap.min.css'); @import url('includes/styles1.css'); @import url('includes/styles2.css&ap ...

Ways to cap the height of elements at predetermined values ("stepped") depending on the content within

After posting a question on this topic here, I am seeking advice on how to implement "step-based heights" for a div element. To further clarify, my goal is to have each box with a height that is a multiple of 400px. For example, if the height is 345px, it ...

Difficulty Encountered when Using Colorbox in Internet Explorer (all iterations)

I've been struggling to get Colorbox working properly on this particular page, even after spending more time than anticipated. The link to the page has been removed for privacy reasons. There's a Colorbox test link at the bottom right corner tha ...

How can you make components appear and disappear dynamically in React with animations?

As I delve into the world of React (coming from a VueJS background), I've encountered what seems to be a problem :) Within my state, I have a boolean value for toggling the visibility of a modal component like this: {showModal && <Modal modalHeade ...

The "pointer" cursor style is simply not functioning in any way

Here is the angular template code I am working with: <!-- Modal --> <ng-template #levelsmodal let-c="close" let-d="dismiss"> <div class="modal-header"> Select the levels you want to show in the table and chart ...

ERROR: When using Nuxt in combination with Vuetify, a common issue arises with reading the property 'email' when it

Every time I attempt to use the v-model two way binding on a Vuetify v-text-field in Nuxt, I encounter an error. I am puzzled by the fact that I receive a TypeError: Cannot read property 'email' of null as soon as input is entered into the text f ...

Skeleton page CSS sub-navigation menu for Internet Explorer 7

I created a webpage using the Skeleton Framework and added a CSS menu with a submenu. While the menu works well in most browsers, I encountered issues with the submenu when using IE7 and lower versions. Instead of appearing below the parent menu item, the ...

Shift the image closer to the top of the sidebar next to the header

I am seeking to adjust the positioning of my circular image in the sidebar so that it aligns with my name in the header. The contact and tech skills sections may also require some tweaking. Although I have a grasp of the concepts of absolute and relative, ...

Display the selected value with JavaScript

Whenever I choose an item from a select dropdown that fetches data from an API, I then add the selected item's value to a table. Everything functions correctly except for when I click on addItem(), which adds the ID value of the selected item to the t ...

Discover the method for selecting an element within a table that includes a style attribute with padding using Jquery

Looking for a way to identify a td element with the padding style in a table I've attempted to locate a td element with the padding style attribute in a table $(Table).find('td[style="padding:"]') or $(Table).find('td[style] ...

Adjusting my menu layout causes my header image to be partially covered

I've been trying to make my menu fixed at the top of my website, but it keeps overlapping into my header image and doesn't look right. I've experimented with different solutions, but nothing seems to work. Here's the CSS code I used th ...

Utilizing Pseudo Elements within the QT Designer Interface

I was attempting to add a vertical line to the left of a button with a hover effect using a pseudo-element in qt-designer styleSheet, but it was not displaying correctly. Here is the code I used: QPushButton{ position: relative; padding: 10px 20px; border: ...

Retrieve the values of a particular key from your Django queryset JSON data and then seamlessly send them over to VueJS

I recently developed a web app using Django2 with Vue for the frontend. I encountered an issue in passing all values of a specific key from JSON data to a JavaScript dictionary value on the frontend. Despite trying to use the += operator to add the data, I ...

The alignment of images loop and videos loop is off

https://i.stack.imgur.com/6o38F.jpg I am facing an issue with a td container in which I am using PHP to loop through a collection of videos and images. Strangely, the videos are displaying higher than the images even though they are both contained within ...

It seems like Flexbox is ignoring the flex-direction: column property set for a header element

I'm a bit confused because it seems like setting flex-direction: column on an element should display the children of that element in a horizontal row. My layout is simple - at the top, I have the logo, navigation links, and some controls. Below that, ...

Exploring the method of accessing one Vue plugin from another plugin with the use of Vue.prototype

I'm currently working on developing a Vue plugin aimed at simplifying the management of authentication state throughout my application. This particular plugin will require interaction with other Vue plugins such as vuex, vue-router, and vue-apollo (fo ...

Provide alternative styling through css in instances where the Google Books API does not provide an image

How can I modify the CSS code to display the author and title of a book when there is no image available from the Google Books API? Currently, users see a custom image linked here, but it's not clear what it represents without the name and author inf ...

Best practices for styling highlighted text when hovered over using CSS

Here is a link to the codepen in question: https://codepen.io/dvreed77/pen/yrwjoM. I am trying to highlight specific text with a large line gap and maintain the hover effect consistently when hovering over individual blocks of text. Currently, the highlig ...