how do i rotate a HTML 3D scene? - html

i want to make a 3d scene made out of squares and then move around without addons
then i started by watching a video about html and 3d graphics, i made this and i have been stuck for 2 days trying to animate the scene, i have tried with javascript to detect the mouse or keyboard but im unable to make it work, im new to css, html and java
i use visual studio code
<!DOCTYPE html>
<html>
<head>
<title>engine 1A</title>
<style>
html, body {margin: 0; padding: 0;}
body {background: black; overflow: hidden;}
#scene
{
perspective: 800px;
transition-duration: 5s;
transition-delay: 2s;
transition-timing-function: linear;
transition-property: width;
}
#keyframes roll {
from {
transform:rotateX(0) rotateY(0);
}
to {
transform:rotateX(360) rotateY(360);
}
}
#mainD
{
width: 500px;
height: 500px;
margin: 200px auto;
}
#boxD
{
width: 500px;
height: 500px;
}
#boxD div
{
position: absolute;
border: 1px solid white;
width: 500px;
height: 500px;
transform-style: preserve-3d;
}
#ZB
{
transform: translateZ(250px) rotateY(180deg)
}
#ZP
{
transform: translateZ(-250px)
}
#XB
{
transform: translateX(-250px) rotateY(90deg)
}
#XP
{
transform: translateX(250px) rotateY(-90deg)
}
#YB
{
transform: translateY(-250px) rotateX(90deg)
}
#YP
{
transform: translateY(250px) rotateX(-90deg)
}
</style>
</head>
<body>
<div id="scene">
<div id="mainD">
<div id="boxD">
<div id="ZB"></div>
<div id="ZP"></div>
<div id="XP"></div>
<div id="XB"></div>
<div id="YP"></div>
<div id="YB"></div>
</div>
</div>
</div>
</body>
</html>
<!-- begin snippet: js hide: false console: true babel: false -->

Related

Issue with running CSS transition with another element's hover

I'm attempting to create a menu that I can use for a website.
I have a nice little graphic for the menu button in the top left corner, and it works when you hover over the bars themselves.
Why is the transition not running while the mouse is hovering over the menu but does when the mouse is over the bars?
css --
.bars:hover .line-top { transform: translateY(9px) rotateZ(45deg); }
.bars:hover .line-middle { transform: rotateZ(135deg); }
.bars:hover .line-bottom { transform: translateY(-9px) rotateZ(135deg); }
.menu-holder:hover ~ .bars .line-top { transform: translateY(9px) rotateZ(45deg); }
.menu-holder:hover ~ .bars .line-middle { transform: rotateZ(135deg); }
.menu-holder:hover ~ .bars .line-bottom { transform: translateY(-9px) rotateZ(135deg); }
.menu-holder {
width: 200px;
position: absolute;
top: 0;
left: -150px;
height: 100vh;
background: red;
transition: transform 1s;
}
.bars:hover ~ .menu-holder{
transform: translateX(150px);
}
.menu-holder:hover {
transform: translateX(150px);
}
.line-top, .line-middle, .line-bottom {
width: 30px;
height: 8px;
border-radius: 28px;
background: black;
margin: 1px;
transition: transform 1s;
}
.bars {
width: 30px;
z-index: 2;
position: absolute;
}
html --
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
</head>
<body>
<div class="bars">
<div class="line-top"></div>
<div class="line-middle"></div>
<div class="line-bottom"></div>
</div>
<div class="menu-holder slider">
</div>
<!-- <script src="script.js"></script> -->
</body>
</html>
P.S. I'm very new to CSS and it may just be a simple mistake
CSS selectors go in one direction. .a ~ .b means "every .b element after .a elements will have the subsequent properties applied to said .b elements". So, your .menu-holder:hover ~ .bars has no effect, as there are no elements with class bars after your menu-holder element.

Why aren't my CSS rules being applied to flip an image?

I have an app that has a two-sided HTML element. When a user clicks a button, I want to "flip" the element. I've been trying to get it to work as shown here. That example includes the following HTML, CSS, and JavaScript.
HTML
<div id="myApp">
<div class="flip-card">
<div class="flip-card-inner">
<div :class="{ 'flip-card-front':true, 'flipped':!isFlipped }">Side A</div>
<div :class="{ 'flip-card-back':true, 'flipped':isFlipped }">Side B</div>
</div>
</div>
<button #click="onButtonClick">Flip</button>
</div>
CSS
.flip-card {
background-color: transparent;
width: 300px;
height: 300px;
perspective: 1000px;
}
.flip-card-inner {
position: relative;
width: 100%;
height: 100%;
text-align: center;
transform: rotateY(180deg);
transition: transform 0.6s;
transform-style: preserve-3d;
box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2);
}
.flipped {
transform: rotateY(180deg);
}
.flip-card-front, .flip-card-back {
position: absolute;
width: 100%;
height: 100%;
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
}
.flip-card-front {
background-color: #bbb;
color: black;
}
.flip-card-back {
background-color: #2980b9;
color: white;
transform: rotateY(180deg);
}
JavaScript
const MyApp = {
data() {
return {
isFlipped: false
}
},
methods: {
onButtonClick() {
this.isFlipped = true;
}
}
}
Vue.createApp(MyApp).mount('#myApp');
There doesn't appear to be any errors. It's just not behaving as I'd expect. Everything looks correct. How do I get the card to flip when someone clicks the button?
UPDATE
This example cleared it up.
Your class is being applied as expected, but you have a CSS specificity problem.
Increase specificity like this:
.flip-card-front.flipped {
transform: rotateY(180deg);
}
Try to replace below code.
this.isFlipped = true;
To
this.isFlipped = !this.isFlipped;

CSS Translate Z transition with perspective causes elements to skew and distort

I'm not sure if I'm missing something with my understanding of translateZ and perspective but I've added a CodePen for the same.
Here's my code:
body {
margin: 0;
height: 100vh;
}
.cards-container {
padding: 100px;
margin: auto;
margin-top: 100px;
transform-style: preserve-3d;
}
.cards-container,
.cards-container * {
height: 400px;
width: 400px;
box-sizing: border-box;
background-color: lightgray;
transition: all ease 1.6s;
/* perspective: 1200px; */
}
.card {
width: 200px;
height: 200px;
padding: 50px;
background-color: lime;
transform-style: preserve-3d;
}
.card-child {
width: 100px;
height: 100px;
background-color: rgb(255, 230, 0);
}
.cards-container:hover {
transform: perspective(1200px) rotateX(50deg) rotateY(20deg) rotateZ(-35deg) translateZ(40px);
}
.cards-container:hover .card {
transform: perspective(1200px) translateZ(80px);
}
.cards-container:hover .card .card-child {
transform: perspective(1200px) translateZ(60px);
}
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Demo</title>
<link rel="stylesheet" href="css/main.css">
</head>
<body>
<script src="index.js"></script>
<div class="cards-container">
<div class="card">
<div class="card-child"></div>
</div>
</div>
</body>
</html>
The issue I'm facing is one that I'm unable to consistently reproduce. If you hover over the cards in my example, you will notice the transitions play smoothly. The intended transition is for the 3 cards to go from a flat layout into a 3D one on hover, where each card raises above its parent. But sometimes when I hover over them, the transition goes all wonky and the whole card itself gets skewed/distorted, goes out of bounds in the z-axis. To reproduce this just try hovering on and off a couple of times over the card and you will notice it happen randomly.
In my opinion it seems to be something with the perspective but I'm out of my depth here considering I'm not even sure how to reproduce it consistently.
Any understanding of this issue is appreciated.
The trick is that you are also applying a transition to perspecitve since it's a part of the transformation creating this bad effect. Perspective need to remain the same even on the non hover state:
body {
margin: 0;
height: 100vh;
}
.cards-container {
padding: 100px;
margin: auto;
margin-top: 100px;
transform-style: preserve-3d;
}
.cards-container,
.cards-container * {
height: 400px;
width: 400px;
box-sizing: border-box;
background-color: lightgray;
transition: all ease 1.6s;
/* perspective: 1200px; */
}
.card {
width: 200px;
height: 200px;
padding: 50px;
background-color: lime;
transform-style: preserve-3d;
}
.card-child {
width: 100px;
height: 100px;
background-color: rgb(255, 230, 0);
}
.cards-container {
transform: perspective(1200px) rotateX(0deg) rotateY(0deg) rotateZ(0deg) translateZ(0px);
}
.cards-container:hover {
transform: perspective(1200px) rotateX(50deg) rotateY(20deg) rotateZ(-35deg) translateZ(40px);
}
.cards-container .card {
transform: perspective(1200px) translateZ(0px);
}
.cards-container:hover .card {
transform: perspective(1200px) translateZ(80px);
}
.cards-container .card .card-child {
transform: perspective(1200px) translateZ(0px);
}
.cards-container:hover .card .card-child {
transform: perspective(1200px) translateZ(60px);
}
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Demo</title>
<link rel="stylesheet" href="css/main.css">
</head>
<body>
<script src="index.js"></script>
<div class="cards-container">
<div class="card">
<div class="card-child"></div>
</div>
</div>
</body>
</html>
In such case, it's better to consider the perspective property instead of perspective() transform function

Reveal animation

I've coded a reveal image animation and have stumbled across an issue when in the creation.
.container{
overflow: hidden;
}
.image {
background-image: url('https://images.wallpaperscraft.com/image/honda_civic_type_r_honda_type_r_honda_129270_3840x2160.jpg');
background-size: cover;
width: 400px;
height: 400px;
animation: 1s ease-out 0s 1 slideInFromLeft;
overflow: hidden;
}
#keyframes slideInFromLeft {
0% {
transform: translatex(-100%);
}
100% {
transform: translatex(0%);
}
}
<div class="container">
<div class="image">
</div>
</div>
The animation seems to be working fine except for it not sliding smoothly. It seems to have a jitter of some sort.
How can I make the animation slide more smoothly?
You could wait for the page/image to load and then trigger the animation to happen. The code below is a crude way of applying the animation class once with js.
window.onload = function() {
var element = document.getElementById('img1');
element.classList.add("show");
element.classList.add("animate");
}
.container{
overflow: hidden;
}
.image {
background-image: url('https://images.wallpaperscraft.com/image/honda_civic_type_r_honda_type_r_honda_129270_3840x2160.jpg');
background-size: cover;
width: 400px;
height: 400px;
opacity: 0;
overflow: hidden;
}
#img1.animate{
animation: 1s ease-out 0s 1 slideInFromLeft;
}
.show {
opacity:1;
}
#keyframes slideInFromLeft {
0% {
transform: translatex(-100%);
}
100% {
transform: translatex(0%);
}
}
<div class="container">
<div id="img1" class="image" >
</div>
</div>
I'd use an <img> element for this and remove it when it loaded, after I pass it's src to the backgroundImage of the parent, as it was already loaded:
let imageDivs = document.querySelectorAll('.image img');
for (var i = 0; i < imageDivs.length; i++) {
imageDivs[i].addEventListener('load', imageLoaded)
}
function imageLoaded(e) {
let div = e.target.closest('div');
div.style.backgroundImage = 'url('+this.src+')';
div.classList.add('loaded');
div.removeChild(div.querySelector('img'));
}
.container{
overflow: hidden;
}
.image {
background-size: cover;
width: 400px;
height: 400px;
transform: translatex(-100%);
overflow: hidden;
}
.image.loaded{
animation: slideInFromLeft 1s cubic-bezier(.5,0,.3,1) forwards;
}
.image img {
height: 0;
}
#keyframes slideInFromLeft {
0% {
transform: translatex(-100%);
}
100% {
transform: translatex(0);
}
}
<div class="container">
<div class="image">
<img src="https://images.wallpaperscraft.com/image/honda_civic_type_r_honda_type_r_honda_129270_3840x2160.jpg">
</div>
</div>
This triggers the animation of a particular <div> (if you have more than one) as soon as that image loaded, rather than triggering all of them after all images in the page have loaded (if you use window.load).
However, this doesn't mean you should load huge resources in your page. Optimizing your images and loading them the right size for current device is a very important step in website optimization. You should use srcset for this purpose.

Mouseover shop scroll effect

I would like to include the mouseover 'Shop Now' effect on my images, I used this code:
<!DOCTYPE html>
<html>
<style>
.container {
style= "width:300px;height:300px;"
left: 0;
Right: 0;
}
.image {
opacity: 1;
display: block;
transition: .5s ease;
backface-visibility: hidden;
}
.middle {
transition: .5s ease;
opacity: 0;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
-ms-transform: translate(-50%, -50%);
text-align: center;
}
.container:hover .image {
opacity: 0.3;
}
.container:hover .middle {
opacity: 1;
}
.text {
background-color: #4CAF50;
color: white;
font-size: 16px;
padding: 16px 32px;
}
</style>
<div class="container">
<img src="img_avatar.png" alt="Avatar" class="image" >
<div class="middle">
<div class="text">Shop Now</div>
</div>
</div>
</html>
But when I run it on my site the scroll effect works for all 3 images at the same time. As shown below:
What can I do to solve this problem? I have been told previously that if I change the container size to just fit the image it should work, but how would I do that?
<!DOCTYPE html>
<html>
<style>
.container {
width:300px; /*edited here*/
height:300px;
/*this syntax is for html tags ONLY: style= "width:300px;height:300px;"*/
left: 0;
Right: 0;
}
.image {
opacity: 1;
display: block;
transition: .5s ease;
backface-visibility: hidden;
}
.middle {
transition: .5s ease;
opacity: 0;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
-ms-transform: translate(-50%, -50%);
text-align: center;
}
.container:hover .image {
opacity: 0.3;
}
.container:hover .middle {
opacity: 1;
}
.text {
background-color: #4CAF50;
color: white;
font-size: 16px;
padding: 16px 32px;
}
</style>
<div class="container">
<img src="img_avatar.png" alt="Avatar" class="image" >
<div class="middle">
<div class="text">Shop Now</div>
</div>
</div>
</html>
you used the wrong syntax for css. style= "width:300px;height:300px;" would be correct if it was in your html like so:
<div class = "container" style= "width:300px;height:300px;"></div>
but in css the style is already implied throught the tags so in css all you need to do is:
.container{
width:300px;
height:300px;
/*and so on*/
}
note: to avoid future problems learn about chrome's inspect tool. It will help you get a better understanding of your page layout and the size of elements and what not. https://developers.google.com/web/tools/chrome-devtools/inspect-styles/
Few short notes:
U cannot use style= "width:300px;height:300px;" within css. Within your example, your first line should be:
.container {
width:300px;
height:300px;
left:0;
Right:0;
}
You can only use the style-attribute within your html, but it is not nessesairy. If you do this, it will bypass your css:
<div class="container" style="width:300px;height:300px;">
You furthermore don't really have to call width and height both, since an image will scale automatically when it has one of these.
With all this being said, I believe this code solves your problem:
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
* {box-sizing: border-box;}
.container {
position: relative;
width: 50%;
width: 200px;
}
.image {
display: block;
width: 100%;
height: auto;
}
.overlay {
position: absolute;
bottom: 0;
background: rgb(0, 0, 0);
background: green; /* Black see-through */
color: #f1f1f1;
width: 100%;
transition: .5s ease;
opacity:0;
color: white;
font-size: 20px;
padding: 20px;
text-align: center;
}
.container:hover .overlay {
opacity: 1;
}
</style>
</head>
<body>
<h2>Image Overlay Title</h2>
<p>Hover over the image to see the effect.</p>
<div class="container">
<img src="https://www.w3schools.com/howto/img_avatar.png" alt="Avatar" class="image">
<div class="overlay">Shop now</div>
</div>
<div class="container">
<img src="https://www.w3schools.com/howto/img_avatar2.png" alt="Avatar" class="image">
<div class="overlay">Shop now</div>
</div>
</body>
</html>