Position <div> over image with CSS 3D transforms like augmented reality - css

I am trying to position a <div> over a photograph of a TV on a wall, so it looks like the <div> is on the TV.
I am sure the solution is in using CSS 3D transforms and so perspective, perspective-origin, transform and transform-origin. However I can't work out values of these which achieve a good result because I'm using trial and error - I don't know the maths.
This is my progress:
And a jsfiddle of it: https://jsfiddle.net/2pye7nc2/
I am setting perspective on the container:
perspective: 500px;
perspective-origin: 210px 382px;
And transform on the element inside it:
transform: translateX(153px) translateY(253px) translateZ(0) rotateX(-12deg) rotateY(-31deg) rotateZ(-20deg);
transform-origin: 0px 150px;
Help is really appreciated.

The best I could do:
.tv .tv-content {
position: absolute;
top: 0;
left: 0;
opacity: 0.75;
width: 392px;
height: 356px;
transform: translateX(193px) translateY(211px) translateZ(0) rotateX(-11deg) rotateY(-40deg) rotateZ(-19.5deg);
transform-origin: 0px 150px;
line-height: 300px;
text-align: center;
font-size: 32px;
background-color: red;
color: blue;
}
https://jsfiddle.net/Lzf2umzf/
Will that help?

Related

Perspective origin and vanishing points

I'm trying to understand how perspective-origin affects vanishing points. I understand that the red square should vanish into the absolute center, but it appears to vanish towards the center-right instead. The lines would converge towards the center-right. I know I'm misunderstanding this somehow, but I don't know what I'm missing. I've read through whatever documentation I could find on this.
.container {
background: gray;
width: 200px;
height: 200px;
perspective: 50px;
perspective-origin: center center;
}
.contained {
background: red;
width: 100%;
height: 100%;
transform: rotateY(45deg);
transform-origin: center left;
opacity: .5;
}
<div class="container"><div class="contained"></div></div>

Full-width div with perspective

I just recently started toying with perspective and 3D transformations, and understand why my div is not showing up at 100% width (even with it set in the CSS). However, for what I am trying to experiment with, I would like the div to stretch across the full width of the browser responsively. I would just use pseudo-classes to give it the perspective effect if it weren't for the text inside needing to have the same perspective.
http://codepen.io/hiremarklittle/pen/OMBQBJ?editors=1100
html, body {
padding: 0;
margin: 0;
font-family: Helvetica;
font-size: 24px;
color: #777;
}
article {
-webkit-perspective-origin: 85% -100%;
perspective-origin: 85% -100%;
-webkit-transform-style: preserve-3d;
transform-style: preserve-3d;
-webkit-perspective: 300px;
perspective: 300px;
width: 100%;
}
div {
background: #1a1e1a;
display: block;
position: relative;
height: 100px;
width: 100%;
line-height: 100px;
text-align: left;
margin: 100px auto 0;
-webkit-transform-origin: 80px 30px;
transform-origin: 80px 30px;
-webkit-transform: rotateY(20deg) translateX(37px);
transform: rotateY(20deg) translateX(37px);
-webkit-backface-visibility: hidden;
outline: 3px solid transparent;
}
If I set the width to like 156% I think it was, it stretched all the way across, but not responsively. I'd imagine there would have to be some sort of calc() algorithm or JS/JQuery involved, but I'd have no idea where to even start.
Thanks in advance
Mark
From your bit of code , a box-shadow would visually do the job,
box-shadow: 50vw 0 #1a1e1a
but what about a img in bg and having content to go all the way to the edge ?
http://codepen.io/anon/pen/EPdpXG?editors=0100

How can I transform this div without transforming the image within?

I tried to make a shape using div and put an image inside. I want the image to maintain its default shape (rectangle or square) without skewing, but when I put image inside, the image skewed with the div. For the div shape I am using transform: skewY(-10deg);
.intro {
width: 180px;
height: 400px;
/* border-radius:50%;*/
cursor: pointer;
position: relative;
background: #fff;
transform: skewY(-10deg);
margin: 35px 35px 35px 0px;
}
.intro img {
width: 100%;
height: 100%;
}
<div class="intro">
<img src="http://lorempixel.com/180/400/sports">
</div>
You are trying to accomplish this: distort the shape of the outer object but keep the inner shape the same. The only way to do that is to transform the inner shape by the negative of the outer shape transform (aka, if your skewY(10deg) on the outer shape, do skewY(-10deg) on the inner), then hiding the overflow.
See this snippet:
.intro {
width: 180px;
height: 400px;
cursor: pointer;
position: relative;
background: #fff;
/* I added the -webkit- prefix as I'm using Safari 8 and
* it wouldn't show up otherwise. Might want to prefix that! */
-webkit-transform: skewY(-10deg);
transform: skewY(-10deg);
margin: 35px 35px 35px 0px;
overflow: hidden;
}
.intro img {
width: 100%;
height: 100%;
-webkit-transform: skewY(10deg);
transform: skewY(10deg);
}
<div class="intro">
<img src="http://lorempixel.com/180/400/sports">
</div>
An annoying sideeffect of this is that your contents will seem cut off. The only way to solve that is to make the inner shape larger than the outer shape an potentially padding the inside. For your image, I'd suggest:
.intro {
position: relative;
}
.intro img {
/* Use min width and heights higher than 100%
* (you might need to experiment here as it depends
* on the angle you chose for your skew) to fill
* the outer shape completely. */
min-width: 110%;
min-height: 110%;
/* Position the element absolute and 50%
* from the top and left */
position: absolute;
left: 50%;
top: 50%;
/* Now add a transform to it to move it with
* half of its width and height, therefore centering it. */
-webkit-transform: skewY(10deg) translate(-50%, -50%);
transform: skewY(10deg) translate(-50%, -50%);
}
Now you could also do width: 110%; height: 110%; left: -5%; top: -5%; and it would accomplish similar results. Play around with it.
Update
As per #vals suggestion, it might be a lot simpeler to just use the scale transform instead of all the positioning mumbo jumbo. Its always the simplest solution thats easiest to overlook:
.intro img {
-webkit-transform: skewY(10deg) scale(1.2, 1.2);
transform: skewY(10deg) scale(1.2, 1.2);
}

Jagged "border" showing due to background colour on wrapper element with border-radius: 50%;

As I was in the process of trying to make an animated figure (transitions on hover), I found out that the background of my <figure> is showing near the edges when I apply border-radius: 50% to it, even though my image should be taking up all available space.
For a quick demo that illustrates the problem, please look at http://codepen.io/anon/pen/KwMMKz
HTML
<figure>
<img src="http://placehold.it/400x400" alt>
<figcaption>Demo</figcaption>
</figure>
CSS
figure {
background-color: red;
width: 400px;
height: 400px;
border-radius: 50%;
overflow: hidden;
position: relative; /* For caption */
}
img {
border-radius: 50%; /* Forced on image for smooth transition */
width: 100%;
transition: opacity 1s ease-out;
}
figcaption {
position: absolute;
top: 100%;
left: 0;
width: 100%;
color: hotpink;
text-align: center;
transition: top 1s ease-out;
}
figure:hover img {
opacity: 0;
}
figure:hover figcaption {
top: 50%;
}
Please note: I know that placing the background-color on figure:hover is a work-around, but I am more interested in the reason why this "jagged border"-like look is appearing.
My guess is that it has to do with AA rendering (or something related) of the browser and that it treats theĀ <figure> element differently than a media element such as <img>, but I can't find any proof of this online. Is this a bug, is it a "feature", or is it something I can actually fix?
Lastly, I also know that I could have used transform: translateY(); here for the animation, but that's not part of my question so please don't provide it as an answer.
UPDATE 17/12 14:03
It appears that this issue is not exclusive to border-radius: 50%. The issue can occur when any wrapping element uses border-radius in combination with overflow: hidden, when the wrapper contains content that is equal or bigger than the wrapper's dimensions.
UPDATE 17/12 14:14
Neither the usage of overflow: hidden on the wrapper element, nor the usage of border-radius on the contained image (or any other child element) seem to be the cause of this as they can be interchanged and the pixelated edge will still appear.
This seems to indicate that this issue is solely caused by 2 DOM elements being in exactly the same place, when any sort of border-radius is applied to the wrapper element and the visible area of the child is limited to that of the parent's.
I've been having same issue and ended up using pseudo element instead of background, kinda like that:
figure::before {
content: '';
display: block;
background-color: red;
width: 400px;
height: 400px;
transform: scale(0.997);
border-radius: 50%;
}
This allowed me to create 'pseudo background' which I later shrinked a little bit with transform: scale(0.997); so it will be just the same size but a bit below visible edge. Of course in your case you would also need to position image absolutely so it is not pushed below by this ::before.
It appears that it is indeed a "feature" of how the browser handles border-radius to give a smooth edge to the rounded corners of a container. The image background is anti-aliased in the same way (but as it is transparent has no effect) as can be seen by setting the img background color.
When the border is anti-aliased it "bleeds" into the background to soften the edges and so you are seeing that around the image as a "jaggy" ring in much the same way you would see a corona around the moon during a full solar eclipse.
the issue is always there, whether the anti-aliased object is covered or not, if you were to draw a circle then anti-alias it, you would see the circle is marginally narrower than the anti-aliased version. Most anti-aliasing algorithms aggregate the surrounding pixels of the object rather than those contained within it.
To overcome it, you'd either need to make your image large enough to cover the space taken up by the anti-aliased edge or reduce the container such that the anti-aliased area is smaller than the image.
You could add a new tag with an opacity of 0 then have that fade in with the image fading out.
figure {
width: 400px;
height: 400px;
border-radius: 50%;
overflow: hidden;
position: relative; /* For caption */
}
background {
background-color: red;
width: 400px;
height: 400px;
border-radius: 50%;
overflow: hidden;
opacity: 0;
position: fixed;
z-index: 5;
transition: opacity 1s ease-out;
}
img {
border-radius: 50%; /* Forced on image for smooth transition */
width: 100%;
transition: opacity 1s ease-out;
position: relative;
z-index: 100;
}
figcaption {
position: absolute;
top: 100%;
left: 0;
width: 100%;
color: hotpink;
text-align: center;
transition: top 1s ease-out;
z-index: 10000;
}
figure:hover img {
opacity: 0;
}
figure:hover background {
opacity: 1;
}
figure:hover figcaption {
top: 50%;
}
<figure>
<background></background>
<img src="http://placehold.it/400x400" alt>
<figcaption>Demo</figcaption>
</figure>
Notice I added the background tag and removed background-color from figure
http://codepen.io/marczking/pen/KwMgaR
So after playing around (used background-image and pseudo-elements, changes nothing...) you notice that this light border is only visible if you apply round corners. So I am assuming here it has to do how the Browser renders the CSS, nothing wrong with the CSS-rules ^^)
<figure>
<figcaption>Demo</figcaption>
</figure>
figure {
background-color: red;
width: 400px;
height: 400px;
border-radius: 100px;
position: relative; /* For caption */
}
figure::before {
content: "";
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
background: url("http://placehold.it/400x400") no-repeat;
border-radius: 100px; /* Forced on image for smooth transition */
transition: opacity 1s ease-out;
}
figcaption {
position: absolute;
top: 100%;
left: 0;
width: 100%;
color: hotpink;
text-align: center;
transition: top 1s ease-out;
}
figure:hover::before {
opacity: 0;
}
figure:hover figcaption {
top: 50%;
}

How to calculate right transformation to create cut off the corner on the div in certain angle using CSS

I want to create effect of page corner cliping like in turn.js, I know that I need two divs the outside one need to have positive rotation and inside one need the same amount but negative, and both need translate, but I don't know how to calculate the right values.
How can I do this for each corner?
Here is my try.
Here is my try, for a cut-off of 20px:
.page-wrapper {
position: absolute;
overflow: hidden;
width: 400px;
height: 300px;
top: 50px;
left: 50px;
right: auto;
z-index: 12;
background-color: blue;
}
.outter-wrapper {
position: absolute;
overflow: hidden;
-webkit-transform-origin: 100% 50%;
-webkit-transform: translateX(-20px) rotate(45deg);
right: 0px;
bottom: -100%;
width: 200%;
height: 200%;
}
.inner-wrapper {
-webkit-transform-origin: 100% 100%;
-webkit-transform: rotate(-45deg) translateX(20px);
background-color: yellow;
width: 50%;
height: 50%;
right: 0px;
position: absolute;
top: 0px;
}
You need to make the outter wrapper bigger than the inner wrapper; if not you are clipping in places that you didn't intended. I have done it 20%%; this way the math is easier.
Also, you need to adjust it carefully so that you still know the coordinates of the transform origin.
And you don't really need to move it in x and y, it's enough to mevo it horizontally.
demo

Resources