This question already has answers here:
Why aren't my absolutely/fixed-positioned elements located where I expect?
(3 answers)
Closed 1 year ago.
html {
scroll-behaivor: smooth;
padding: 0;
margin: 0;
}
#skip-to-main-content {
position: absolute;
transform: translatey(0);
display: block;
background: grey;
width: 100%;
}
.box {
height: 100px;
width: 100px;
background: green;
margin-top: 200px;
}
<div id="skip-to-main-content">Skip to main content</div>
<div class="box"></div>
With the transform: translatey(0) I was expecting the div "skip-to-main-content" to be positioned at the top of the page. However, it's positioned at the top of the div "box".
If I change from translateY(0) to top: 0. Then it appears at the top of the page. How come translateY is acting differently? It's almost like translateY is not honoring the position absolute. I thought the position: absolute would have take it own of the regular flow.
Thanks.
The transform property will apply relative transformation. It is usually used for animation more than positionning, and doesn't work in pair with position property.
Remove your absolute positioning and use relative. Then you can use transform: translateY(50%) translateY(-50%); to place at the top of the page.
html {
scroll-behaivor: smooth;
padding: 0;
margin: 0;
}
#skip-to-main-content {
position: relative;
transform: translateY(50%) translateY(-50%);
display: block;
background: grey;
width: 100%;
}
.box {
height: 100px;
width: 100px;
background: green;
margin-top: 200px;
}
<div id="skip-to-main-content">Skip to main content</div>
<div class="box"></div>
(Note: typo in the code given in the question - translatey.)
transform: translateY moves the element relative to where it is positioned.
If you see translateY(-50%) that means the element will be moved upwards by half of its own height.
If you see translateY(0) [as in the question] that means the element isn't moved at all.
If you see translateY(50px) that means the element moves down by 50px from its original position.
Note that in any translation the element moves visually but it does not move within the overall content, this translation does not effect the positioning of other elements.
To get an absolutely positioned element to go to the top of the page, as is described in the question, it needs to have top: 0 set AND that will be relative to the first ancestor that has position set. So be careful that none of the parents/grandparents that you don't want it to be positioned in have position relative or absolute set. In this special case the system will go 'all the way up' as there is no intervening positioned element.
Taking the given code, and as it's an SO snippet realising that there will be a body element encompassing the content of the page, we position the element in relation to that:
html {
scroll-behaivor: smooth;
padding: 0;
margin: 0;
}
#skip-to-main-content {
position: absolute;
top: 0;
display: block;
background: grey;
width: 100%;
}
.box {
height: 100px;
width: 100px;
background: green;
margin-top: 200px;
}
<div id="skip-to-main-content">Skip to main content</div>
<div class="box"></div>
This question already has answers here:
I have position but z index is not working
(1 answer)
Why can't an element with a z-index value cover its child?
(5 answers)
Closed 3 years ago.
UPDATE: This question was marked as duplicate by a friend, but I think the answer is still very valuable. I looked into those answers in duplicate questions and no one mentioned transform-style: preserve-3d can do transform without creating new stacking context. So this problem is more specific than how z-index works. It's also about how transform works.
I was trying to add some animation when hovering over a div element. But when I added transform in hover, its pseudo child element's background color covered div's. It seems that this wired behavior only happens when using transform. I want to know what's the mechanism behind this behavior.
In the following codepen example, the first one is hover with transform, the second one is normal hover.
https://codepen.io/neirongkuifa/pen/PgaEZd
.container {
width: 100px;
height: 100px;
background-color: red;
position: relative;
margin-bottom:100px;
}
.move:hover {
transform: translateY(3px);
}
.changeColor:hover{
background-color:white
}
.container::after {
content: '';
display: inline-block;
position: absolute;
top: 0;
left: 0;
background-color: green;
width: 150px;
height: 150px;
z-index: -1;
}
<div class="container move">Content</div>
<div class="container changeColor">Content</div>
You are creating a new stack context, and the z-index behaves differently.
Your best solution is to handle everything using transforms. I have added a transformZ negative in the pseudo to move it backwards, and a preserve-ed on the item to make this work:
.container {
width: 100px;
height: 100px;
background-color: red;
position: relative;
margin-bottom:100px;
transform-style: preserve-3D; /*added*/
}
.move:hover {
transform: translateY(3px);
}
.changeColor:hover{
background-color:white
}
.container::after {
content: '';
display: inline-block;
position: absolute;
top: 0;
left: 0;
background-color: green;
width: 150px;
height: 150px;
z-index: -1;
transform: translateZ(-1px); /*added*/
}
<div class="container move">Content</div>
<div class="container changeColor">Content</div>
I am trying to make an opening book animation with CSS transitions similar to a card flip animation except with another card behind it.
When I create a single card flip it works fine in chrome. But if I put it inside a parent div in order to place another card behind it the back of the card no longer shows.
HTML
<div class="scene">
<div class="turncard">
<div class="turncard-front">
<div class="turncard-outside turncard-side">
Front!!!<br/>I don't work
</div>
<div class="turncard-inside turncard-side">
Back!!!<br/>Can you see me?
</div>
</div>
</div>
</div>
CSS
.scene {
margin-left: 200px;
perspective: 6000px;
}
.turncard {
width: 200px;
height: 200px;
margin-top: 50px;
transform-style: preserve-3d;
}
.turncard-front {
height: inherit;
width: inherit;
transition: transform 0.6s;
transform-origin: top left;
}
.turncard-side {
height: inherit;
width: inherit;
position: absolute;
backface-visibility: hidden;
background-color: green;
text-align: center;
}
.turncard-outside{
z-index: 1;
}
.turncard-inside {
transform: rotateY(180deg);
z-index: -1;
}
.turncard-front:hover {
transform: rotateY(180deg);
}
Both the working version (without a parent div) and non-working example (with the div) are shown in this fiddle: http://jsfiddle.net/bxLa4kwu/1/
Stick this property on .turncard2-front:
transform-style: preserve-3d;
http://jsfiddle.net/bxLa4kwu/3/
This property tells it to preserve the 3D position of children of the turncard2-front element (e.g. inside and outside of the page) when turncard2-front is css transformed.
Be aware this doesn't work in IE11 as the property isn't supported (but you probably knew that as the first example doesn't work either in IE).
I'm trying to make a splash page on my website with 2 large buttons, each a right angled triangle, and both join by the longest side to create a square. Basically I'm looking to find out how to make non-rectangular buttons in css.
I have no idea if this is even possible though, and cannot find anything online explaining similar techniques for buttons which are not rectangular, and i'm not particularly skilled in css. A push in the right direction would be very helpful!
A very old (unanswered question) deserves an answer.
You could use a nested div element in which the parent has an overflow set to hidden, with the child element rotated.
Here is a basic example: (please note: jQuery only required for demo)
$('.tri').click(function() {
alert("triangle clicked!");
});
.wrap {
height: 200px;
width: 200px;
position: relative;
overflow: hidden;
margin: 2px auto;
}
.wrap .tri {
position: absolute;
height: 70%;
width: 70%;
background: tomato;
transform-origin: bottom left;
bottom: 0;
transition: all 0.6s;
left: 0;
cursor: pointer;
transform: rotate(45deg);
}
.wrap2 {
transform: rotate(180deg);
}
.wrap .tri:hover {
background: black;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="wrap">
<div class="tri"></div>
</div>
<div class="wrap wrap2">
<div class="tri"></div>
</div>
Translating an elements Y axis 50% will move it down 50% of its own height, not 50% of the parents height as I would expect. How do I tell a translating element to base it's translation percentage on the parent element? Or am I not understanding something?
http://jsfiddle.net/4wqEm/2/
When using percentage in a transform translate on a non-SVG element, it refers to the width or height of itself. Take a look at https://davidwalsh.name/css-vertical-center (demo):
One interesting thing about CSS transforms is that, when applying them with percentage values, they base that value on the dimensions of the element which they are being implemented on, as opposed to properties like top, right, bottom, left, margin, and padding, which only use the parent's dimensions (or in case of absolute positioning, which uses its closest relative parent).
On an SVG element, a transform percentage refers to the size of the parent instead!
Here is a pen:
https://codepen.io/trusktr/pen/gOdwWXv
svg, [outer] {
border: 1px solid black;
}
rect {
transform: translate3d(50%, 50%, 0);
}
[inner] {
background: black;
transform: translate3d(50%, 50%, 0);
}
<svg width="100" height="80">
<rect width="20" height="20" />
</svg>
<div outer style="width: 100px; height: 80px;">
<div inner style="width: 20px; height: 20px;"></div>
</div>
Strange, huh?
You can use vw and vh to translate based on the viewport size
#keyframes bubbleup {
0% {
transform: translateY(100vh);
}
100% {
transform: translateY(0vh);
}
}
What works for me using only CSS is:
.child {
position: relative;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
/* Backward compatibility */
-webkit-transform: translate(-50%, -50%);
-moz-transform: translate(-50%, -50%);
-o-transform: translate(-50%, -50%);
-ms-transform: translate(-50%, -50%);
}
How it works:
top and left positioning move child widget according to parent coordinates. Child widget's top-left corner will appear exactly in the center of parent (this is not what we want at this time).
translation will move child widget -50% to top and left based on its size (not the parent). It means, widget's center point will be moved exactly where top-left point was - which previously was set up as center of a parent, and this is what we want.
To use percentage in the translate property, you have to use Javascript : http://jsfiddle.net/4wqEm/27/
HTML code :
<div id="parent">
<div id="children"></div>
</div>
CSS code :
#parent {
width: 200px;
height: 200px;
background: #ff0;
}
#children {
width: 10%;
height: 10%;
background: #f00;
}
Javascript code :
parent = document.getElementById('parent');
children = document.getElementById('children');
parent_height = parent.clientHeight;
children_translate = parent_height * 50/100;
children.style.webkitTransform = "translateY("+children_translate+"px)";
I hope I could help you and say me if you have any other problem.
Your statement is absolutely right about the percentages coming from the very translated element. Instead of using translate property in your case you should be using absolute positioning to stay relative to the parent div. I absolutely positioned vertically your red div here:(don`t forget about adding position relative to the parent div.It has to be positioned other than static default):
js fiddle pen here
body {
margin: 0;
width: 100%;
height: 100%;
}
body > div {
width: 200px;
height: 200px;
background: #ff0;
position: relative;
}
body > div > div {
width: 10%;
height: 10%;
-webkit-transform: translateY(-50%);
background: #f00;
position: absolute;
top: 50%;
}
You can also use one extra block and use the transition for it except the child node
HTML code :
<div id="parent">
<div id="childrenWrapper">
<div id="children"></div>
</div>
</div>
css should be something like this
#parent {
position: relative;
width: 200px;
height: 200px;
background: #ff0;
}
#childrenWrapper{
width: 100%;
height: 100%;
}
#children {
width: 10%;
height: 10%;
background: #f00;
}
You can make the element absolute positioned and use left and top property to take the percentage value as parent.
Its forked with positioning required on the following URL
working sample
body {
margin: 0;
width: 100%;
height: 100%;
}
body>div {
position: relative;
width: 200px;
height: 200px;
background: #ff0;
}
body>div>div {
position: absolute;
left: 50%;
top: 50%;
width: 10%;
height: 10%;
background: #f00;
transform: translate(-50%, -50%);
}
notes :
you can absolute positioning of your red square by changing parent element to position relative
then using 50% top and 50% left will position red square according to its upper left corner
using transform:translate(-50%,-50%) will position red square according to its center
The solution to this problem is not to use translate at all. When you are translating an element, the percentage you select is based on it's own height.
If you want to position the element based on the parent's height, use top: 50%;
So the code will look like this:
body {
margin: 0;
width: 100%;
height: 100%;
}
body > div {
width: 200px;
height: 200px;
background: #ff0;
position: relative;
}
body > div > div {
position: absolute;
top: 50%;
width: 10%;
height: 10%;
/* -webkit-transform: translateY(50%); */
background: #f00;
}