Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

CSS CSS Transitions and Transforms Adding 3D Effects with CSS Build a Rotating 3D Cube

Andrew Whatmore
seal-mask
.a{fill-rule:evenodd;}techdegree
Andrew Whatmore
Full Stack JavaScript Techdegree Student 8,971 Points

Making cube responsive + changing the aspect ratio

There are a couple of questions I have in terms of how we can make this cube work for us in different situtations:

This tutorial uses hard-coded pixel values, meaning the cube:

  1. is not responsive ie does not adjust with screen width
  2. ties us to this particular aspect ratio

What is the best way to make the cube responsive? How would we go about eg replacing each pixel value in the tutorial with relative units?

  • Is there a formula for calculating the transform values in relation to the cube size if we use relative units?
  • Is there another way we could achieve a responsive cube?

How would we go about using a different aspect ratio for the cube?

  • Similarly, is there a formula for calculating the transform values based on the cube size we are using, that we can apply to different aspect ratios (including if we use relative units)?

Many thanks in advance,

Andrew

Andrew Whatmore
seal-mask
.a{fill-rule:evenodd;}techdegree
Andrew Whatmore
Full Stack JavaScript Techdegree Student 8,971 Points

OK, to part-answer my own question:

  • it looks like the translateZ and translateX values are meant to be half the width? And so we can change the aspect ratio just by changing the width and height of the elements, but making sure that the translateZ/translateX values are half the width at the end. Is that correct?

1 Answer

Andrew Whatmore
seal-mask
.a{fill-rule:evenodd;}techdegree
Andrew Whatmore
Full Stack JavaScript Techdegree Student 8,971 Points

Attempt at responsive 3D rotating cube

I seem to have made the cube responsive using the following code under ‘1’. If anyone has any feedback, or knowledge of a better method, I would be grateful to hear it!

The below method is based on the knowledge that the ‘translateX’ and ‘translateZ’ values used by the sides of the cube, are meant to be half the width of the cube container (with translateZ being the negative version). I described this in my answer above.

1. Use % for parent width, set sides of cube using CSS variables, update variables using JS

Using % may be best as far as I can see, as the cubes will adjust to their parent containers. This is especially convenient if the cube parents are inside containers that are already responsive. Other units may go beyond parent containers, eg making them bigger than grid columns, and cause elements to overlap.

The problem with this method is we won’t be able to set the transform values to half this in CSS, as you can’t set transform to a %. To get around this, use JS:

  • in CSS, have a ::root pseudo-element which contains variables to represent the translateX and translateZ properties used by the sides of the cube (here, they have been given default amounts, but these will change on page load):
:root {
  --pos-translate-amount: 170px;
  --neg-translate-amount: -170px;
}
  • use these variables as placeholders for the respective properties for the sides of the cube:
.front {
  transform: translateZ(var(--pos-translate-amount));
}

.back, .back-overlay {
  transform: translateZ(var(--neg-translate-amount)) rotateY(270deg);
  transform-origin: center left;
}

.left {
  transform: rotateY(-270deg) translateX(var(--pos-translate-amount));
  transform-origin: top right;
}

.right {
  transform: translateZ(var(--neg-translate-amount) rotateY(180deg);
}

Then in JS, we can calculate and update these variables on page load and on page resize. Since the numbers for these variables will be half the width of the parent cube container, we will get the value for this width, then use it to calculate and update the values for these variables. We do this as follows:

  • get the root element, which contains  variables we will update
let root = document.querySelector(':root');
  • get the first cube element, so we can extract it's width
const cube = document.querySelector('.photo-cube');
  • create object to hold the css object returned by getComputedStyle
let cssObj = {};
  • create variable to hold with width of the cube we will use to calculate the translate variables.
let cubeWidth = Number(0);
  • callback for page load and screen resize events, which will update variables used by sides of cube
    • get the styles of the parent cube container using getComputedStyle, then get the width of it from the object using it's 'width' property (which will return the value as px).
    • use the width to update the variables used by the sides of the cube
    • the pos-translate-amount value is half the width of the cube; neg-translate-amount is the same but negative
function setTransformAmounts() {
  cssObj = window.getComputedStyle(cube, null);
  cubeWidth = parseInt(cssObj.width);
  root.style.setProperty('--pos-translate-amount', `${Number((cubeWidth / 2))}px`);
  root.style.setProperty('--neg-translate-amount', `${Number(-(cubeWidth / 2))}px`);
}
  • on page load + resize, run the function to update variables used by sides of the cube
addEventListener("load", setTransformAmounts);
addEventListener("resize", setTransformAmounts);

Other potential methods

2. Use ‘vw’ relative unit

If not using %, another option could be to use ‘vw’ to set things relatively to the viewport width. The transform values can then be set to half that, with no need for JavaScript. However, using vw would vary the size a lot depending on screen width, so we would have to use enough media queries to account for this. Also, we would have to make sure that the size never exceeded the parent column container. This would have to be checked manually, which isn’t ideal.

3. Other relative units

Other relative units like em won’t work as they are relative to font-size, and don’t usually adjust with screen width. This will mean they could exceed their parent containers in size and cause layout issues.

Once again, I would be very grateful if anyone has any feedback or better suggestions.

Many thanks in advance,

Andrew