I have a menu and certain elements have dropdowns. These elements have variable widths. I want the dropdown to be horizontally centered beneath its particular element. The dropdown itself always has a fixed width.
.container {
display: inline-block;
position: relative;
}
.dropdown {
display: none;
top: 100%;
position: absolute;
width: 100px;
}
.container:hover .dropdown {
display: block;
}
http://jsfiddle.net/8AauA/
I've tried using margin-left/left with percentages or offsetting the fixed width of the element, but I can tell that this is not centered -- especially for all containers. Is it possible to do this via CSS?
If the dropdowns always have fixed widths, you could position them by left: 50% which is relative to their containing block's width and then align them center by a negative margin as the half of their width.
Example Here
.dropdown {
/* other styles here... */
left: 50%;
margin-left: -50px; /* = width / 2 */
}
However if they have dynamic widths, you could use CSS3 translateX() function instead of negative margins to achieve the desired result
Example Here
.dropdown {
/* other styles here... */
left: 50%;
-webkit-transform: translateX(-50%);
-moz-transform: translateX(-50%);
-ms-transform: translateX(-50%);
-o-transform: translateX(-50%);
transform: translateX(-50%);
}
It's worth noting that transforms are supported in IE9+
I think the best approach for this issue is
.dropdown {
/* other styles here... */
left: 0;
right: 0;
margin: 0 auto;
}
You may center position:fixed element with this approach as well!
Related
Here is a short codepen of a simple css animation that I'm struggling to work with. Code also below:
.navscroll {
width: 100%;
height: 100px;
padding: 5px;
overflow: hidden;
position: relative;
background-color: red;
}
.navscroll div {
position: relative;
width: 200px;
height: 100%;
line-height: 50px;
text-align: center;
background-color: blue;
opacity: 1;
border-radius: 5px;
transform: translateX(100%);
animation: navscroll 15s linear infinite;
}
#keyframes navscroll {
0% {
transform: translateX(100%);
}
100% {
transform: translateX(-100%);
}
}
<div class="navscroll">
<div>Why arent these</div>
<div>Side by side</div>
<div>or sliding across the WHOLE navbar</div>
</div>
Its supposed to be a scrolling navbar of divs, but I'm having two issues:
The inner divs are stacking vertically, not horizontally...
The inner divs are scrolling across only a small percentage of the nav bar / outer div...
Ideally, if there were many divs in the navscroll div, only 5-6 of them would display anytime on the screen, although the navbar would always be scrolling and those other divs would make their way onto the screen eventually. (similar to stock tickers ticking across the top of the TV screen). Any help with this is appreciated, thanks!!
div is a block level element (means it has display: block; by default). These create a line break before and after themselves. Use display: inline-block; and make sure they align properly using vertical-align: middle;.
2nd problem: translateX(100%) here the percentage does not refer to the parent element, but to the div being animated.
.navscroll {
width: 100%;
height: 100px;
padding: 5px;
overflow: hidden;
position: relative;
background-color: red;
white-space: nowrap;
}
.navscroll div {
position: relative;
width: 200px;
height: 100%;
line-height: 50px;
text-align: center;
background-color: blue;
opacity: 1;
border-radius: 5px;
transform: translateX(100%);
animation: navscroll 15s linear infinite;
/* this does the magic: */
display: inline-block;
vertical-align: middle;
}
#keyframes navscroll {
0% {
left: 100%;
}
100% {
left: -100%;
}
}
<div class="navscroll">
<div>Why arent these</div>
<div>Side by side</div>
<div>or sliding across the WHOLE navbar</div>
</div>
As per your question about how to create a snippet here:
The inner divs are stacking vertically because the default styling for a div is display: block. Adding the styles display: inline-block; vertical-align: top; to your .navscroll div rules will set them side by side, aligned to their top edges.
The animation is starting in the middle, and not all the way to the right like you intend because of how transform: translate() works. transform refers to the object being transformed, not its parent. So, translating something 100% of it refers to the width of the object. Try animating the position, something like this instead:
#keyframes navscroll {
0% {
left: 100%;
}
100% {
left: -600px;
}
}
EDIT: Also, remove the initial transform: translateX(100%); and you can simply animate the left position to -600px (3x the width of the each block).
I need to render a frame (ie, a picture frame around a picture) by rotating an image:
0 degrees for the left
90 for the top
... and so on.
As far as I can tell there isn't a border-image-left|right|top|bottom property, although this would work too - please correct me if I'm wrong.
It seems I'll need to use the border-image property. Does anyone know if possible to rotate the image depending on the side?
I guess the other messy options would include
Creating four div's around the image
Manually generating a frame border image (this won't really work as 1. we've got over 300 images, and 2. the frames need to be used on images with different aspect ratios... )
Edit: 'depending on the side' = 0 degrees for left, 90 degrees for top, 180 degrees for right, 240 for bottom... See image below for an example.
Left hand border image
Partially forced, but wrapping it in a div and span and playing with pseudo elements and transforms seemed to work.
The image is wrapped in an .img-container div and a span, and the ::before and ::after elements are absolute positioned around the image.
Here's the markup:
<div class="img-container">
<span>
<img src="https://unsplash.it/300/300?image=200">
</span>
</div>
And the styling:
.img-container, span, img{
display: block;
position: relative;
}
/* Image border general */
.img-container::before,
.img-container::after,
span::before, span::after{
content: "";
position: absolute;
left: -30px;
top: 50%;
width: 30px;
height: 100%;
transform: translateY(-50%);
background-image: url("https://i.stack.imgur.com/0UI1w.png");
background-size: 100% 100%;
z-index: 2;
}
/* Specific to the right border */
.img-container::after{
left: auto;
right: -30px;
top: 50%;
transform: translateY(-50%) rotate(180deg);
}
/* Top and bottom border general */
span::before,
span::after{
top: 0;
left: 50%;
transform: translate(-50%, -50%) rotate(90deg);
}
/* Just the bottom */
span::after {
top: 100%;
left: 50%;
transform: translate(-50%, -50%) rotate(270deg);
}
May be a little much
Here's a fiddle
Im trying to figure out how to make shopping cart tab that would be positioned on the right corner and also rotated 90 degrees. The rotation naturally mixes the position but maybe there's a workaround of wrapping to different wrappers etc....
Extra points if there wouldn't need to define width. I don't care about older browsers
How about using transform-origin? See DEMO.
Relevant CSS:
#box {
position: relative;
}
.bg {
right: 40px; /* same as height */
height: 40px;
transform: rotate(-90deg);
transform-origin: 100% 0;
position: absolute;
line-height: 40px; /* same as height, for vertical centering */
}
Ana's answer is excellent and pointed me in the right direction, but I realised you could achieve the same effect without having to explicitly set the height, line-height and position for the element you want to move - instead, just set translate(0, -100%):
body {
margin: 0;
}
#box {
position: relative;
}
.bg {
right: 0;
padding: 1em;
transform: rotate(-90deg) translate(0, -100%);
transform-origin: 100% 0;
position: absolute;
background: #FF1493;
}
<div id="box">
<div class="bg">
<div class="txt">He's not the Messiah. He's a very naughty boy.</div>
</div>
</div>
...and a jsFiddle for good measure.
To rotate text at 90° using CSS, consider using writing-mode.
Set position: relative; on the parent div, then use something like this on the rotated element:
#rot {
position: absolute; /* only handy here because its parent is set to `position: relative;` */
left: 0;
top: 0px;
/* writing-mode: sideways-lr; /* Webkit browsers don't support `sideways-lr` yet */
writing-mode: vertical-rl; /* `vertical-rl` and a rotation will achieve the same effect */
transform: scaleX(-1) scaleY(-1);
height: 100%;
background: rgba(0, 0, 0, 0.1);
text-align: center;
line-height: 2.85;
color: white;
font-weight: bold;
}
You'll end up with a div stacked on the side of your parent div, with the text at a 90° angle.
This way you don't have to think about the rotation origin.
If you need to position wrapper div.and rotate child div so that its always centered vertically and horizontally, try something like this!
.togglewrap{
position:relative;
float:left;left:20%;top:0;
width:30px;
height:120px;
background-color: #ffde21;
}
.sbartoggle {
background:#f5f5f5;
position:absolute;
left:0;
top:0;
right:0;
bottom:0;
margin:auto;
width:100%;
height:30px;/*equal to parent width*/
line-height:30px;/*center text*/
transform: rotate(-90deg);
background-size:10px 10px;
}
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;
}
I want my div to show on top of everything I put 100% width and height and it show above a lot of control except some have css z-index and other things. I tried to set the div z-index to a big number but this did not work.
{
width: 100%;
height: 100%;
top: 5px;
left: 0px;
background-color: #FFFFFF !important;
padding: 10px;
overflow: hidden;
visibility: visible;
display: block;
z-index: 500 !important;
position: relative;
}
Since you want to cover the whole screen, I recommend this:
#overlayDiv {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index:99;
}
Note, you don't have to set the display and visibility properties. Also, don't set padding or margin on this element! If you want it to have a padding, set a margin on its child/children.
Also, make sure that the DIV in question is a direct child of the BODY element.
In order to pull an html element out of the natural flow of how the elements are layed out on the screen you need to use position: absolute. This will allow the element to become a layer above the other elements (assuming that the z-index value is greater than all other's).
Right now your element seems to have position: relative.
Probably the issue is related to position:relative. Set it to absolute instead, and if you need to offset the element, use margin instead of top/left.
.centered {
position: fixed;
top: 50%;
left: 50%;
/* bring your own prefixes */
transform: translate(-50%, -50%);
}