How do I centre absolutely positioned content of unknown width? - css

Before someone asks me why the hell I would want to do this let me come straight out and tell you. That way one of you clever peeps out there can tell me a far better way...
I'm making a viewer for paintings which should stretch to fill the page, well 90% of the height of the screen to be precise. I want to fade the paintings in one over the other and want to center each of them in the middle of the screen.
To fade the paintings in over each other I need to position them 'absolute' to stop them from stacking. Here's where the trouble comes. Ever since I've set them to absolute, every method I use to center the containing div hasn't worked.
Part of the problem is that I'm not setting any width for the paintings as I want them to dynamically size themselves to fill 90% of the user's screen.
I've found a hundreds of methods for centering absolute content and believe I might need to shrink wrap the containing div. However I've not had any success as of yet.
HTML-
<div id="viewer_div">
<img src="" id="first" />
<img id="second" class="hidden"/>
</div>
Style Sheet
#viewer_div {
width:1264px;
}
img {
height:90%;
display:block;
margin-left: auto;
margin-right:auto;
}
The above gives me the desired effect, but doesn't allow me to position the images absolute. Can anyone suggest a way of centering the images but also allows me to fade one over the other?

Pushing the element left by 50% of its width and then translating it horizontally by 50% has worked for me.
.element {
position: absolute;
left: 50%;
transform: translateX(-50%);
}
I found the concept in the following link, and then I translated to fit my horizontal align needs: https://gist.github.com/colintoh/62c78414443e758c9991#file-douchebag-vertical-align-css

Either use JavaScript to calculate the width and move it,
use a CSS hack to move the element right and left by 50%,
or don't absolutely position it.
This answer is incredibly short, but it is to the point. If you require something to be centralised (meaning you would like the browser to determine where the centre point is, and position it there), then you can't use absolute positioning - because that takes away control from the browser.
To fade the paintings in over each other I need to position them
'absolute' to stop them from stacking.
This is where your problem lies. You have assumed that you need absolute positioning for the wrong reason.
If you are experiencing problems placing elements on top of each other, wrap the images in an absolutely positioned container which is 100% width and has text-align: center
If you do feel that absolute positioning is necessary, the following hack can be used to achieve your desired results:
div {
position: absolute;
/* move the element half way across the screen */
left: 50%;
/* allow the width to be calculated dynamically */
width: auto;
/* then move the element back again using a transform */
transform: translateX(-50%);
}
Obviously the above hack has a terrible code smell, but it works on some browsers. Be aware: this hack is not necessarily obvious to other developers, or other browsers (especially IE or mobile).

To go off of Samec's answer, you can also use this to center an absolute position element vertically and horizontally of unknown dimensions:
#viewer_div {
position: relative;
}
#viewer_div img {
position: absolute;
left: 50%;
top: 0%;
transform: translate(-50%, 50%);
}

Centering div with position: absolute and width: unknown:
HTML:
<div class="center">
<span></span>
<div>
content...
</div>
</div>
CSS:
.center{
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
display: grid;
grid-template-columns: auto auto;
/* if you need the overflow */
overflow: auto;
}
You can use this solution even if the content is wider than the screen width, and don't need to transform: translate (which can blur elements)
How it works:
Grid will insert a span before the first auto, and insert a div right before the second auto, and you get:
span(0px) - auto - div(...px) - auto
auto will be equal to each other.
Same for vertical centering, but write grid-template-rows instead of a grid-template-columns

2021
A modern approach to absolutely centered content with grid and inset
The inset CSS property is a shorthand that corresponds to the top, right, bottom, and/or left. MDN
#viewer_div {
display: grid;
place-items: center;
position: absolute;
inset: auto 0;
}
*,
::after,
::before {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
}
body {
width: 100vw;
height: 100vh;
background-color: hsl(201, 27%, 10%);
position: relative;
}
#viewer_div {
display: grid;
place-items: center;
position: absolute;
inset: auto 0;
background-color: hsl(197, 7%, 21%);
color: white;
}
<div id="viewer_div">
<h1>Title 2021</h1>
<img src="https://via.placeholder.com/180x100.png/09f/fff" id="first" />
</div>

Related

Positioning text over an image so that it always points to the same spot in the image even when resizing the browser

I am currently building a website with weblflow but run into a problem that someone here might be able to help me with. The is an issue I have for multiple projects, so I would really appreciate someone's help.
Basically, if you have an image full screen size (set as background image, 100vw and 100vh), and then want to put headings/labels on top of that image pointing to specific sections in that image, how do I get these headings/labels always move with the image when someone would resize the browser?
As for now I used absolute positioning for the headings/labels and used % margins to position them where I want them to point to on the image. The image itself I have set to position relative. However, with that solution the headings/labels never exactly continue to point to the same spot on the image when resizing the browser.
I think the main issue is that when someone only changes the browser's width, the image gets (for example) smaller bc it keeps it's ratio. Vertically the headings/labels don't move bc the height was unchanged, it's just the browser's width that was changed. So horizontally it's still fine but vertically the headings are off now since the image got smaller due to resizing the browser's width. So I guess I do know why it's not working but I don't know how to fix this. If someone has a solution for this, please let me know.
As an example: if you open this page: http://nestin.bold-themes.com/classy/ and scroll down to the section ‘True value is always inside’, there is an image with 5 numbered labels, no matter how you resize the browser, these labels/numbers stay in the same spot of the image. I see this quite often on websites. How was this achieved?
Would appreciate any help!
You create a parent wrapper, put inside the image and all the divs.
the parent is relateive and the divs are absolute.
here's a small demo.
* {
box-sizing: border-box;
margin: 0;
}
img {
max-width: 100%;
display: block;
width: 100%;
}
.parent {
position: relative;
}
.parent .box {
position: absolute;
width: calc(1.6vw + 10px); height: calc(1.6vw + 10px);
border-radius: 50%;
background-color: #fff;
display: -webkit-box;
display: flex;
-webkit-box-pack: center;
justify-content: center;
-webkit-box-align: center;
align-items: center;
}
.parent .box.window {
top: 0;
left: 39%;
}
.parent .box.light {
top: 16%;
left: 46%;
}
.parent .box.pool {
top: 90%;
left: 50%;
}
.parent .box.plant {
top: 55%;
left: 3%;
}
<div class="parent">
<div class="box plant">1</div>
<div class="box window">2</div>
<div class="box light">3</div>
<div class="box pool">4</div><img src="https://images.pexels.com/photos/4075088/pexels-photo-4075088.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260" alt=""/>
</div>
https://codepen.io/ShadiMouma/pen/BaKYyYX?editors=1100
You can achieve this with percentage positioning. For example,
In the parent div
position: relative;
In the child div
position: absolute;
top: 50%;
left: 30%;
Now the child div will always position itself 50% from the top and 30% from the left of the parent div. It does not matter what size the parent div is. I suggest you take a parent div and put the image and texts inside it.
Your example website also uses this technique.
check their code here
Another technique would be using HTML canvas. But for something simple like this, HTML canvas would be overkill.

Make absolute positioned nested child the width of container

I'm essentially displaying a banner image on a page. At the base of that image is an overlay (the abs. pos. div) with a semi-transparent background image to make a "see through" effect. Everything is positioned properly and working fine except the overlay at a width of 100% expands outside of my container div. I've tried setting the overflow to hidden of the container div but that does not seem to work. My parent container has a position relative as well. This is responsive so the overlay with need to shrink and expand to the image width. Here's my code:
.hero-img-wrap {
position: relative;
margin-top: 35px;
padding-left: 15px;
padding-right: 15px;
}
.hero-img-wrap img {
width: 100%;
height: auto;
}
.hero-img-wrap .trans-overlay {
position: absolute;
bottom: 0;
z-index: 9;
height: 19px;
background-image: url('../images/semi_transparent_white.png');
width: 100%;
}
<div class="hero-img-wrap">
<img src="images/banner_image.jpg" alt="">
<div class="trans-overlay"></div>
</div>
I could pull this off with JQuery but I'd like to avoid that. For what it might be worth - this code is within a Bootstrap 3 column.
Since you've defined the height, why not a negative value
position: relative;
top: -19px;
Just a thought, heres a fiddle for ya
http://jsfiddle.net/g11yggap/
Try
Width:inherit;
On overlay div

Trouble (vertically) Centering Text in another DIV with relative % sizing

Disclaimer: I don't believe this is a duplicate as I'm using relative sizes to produce a full screen grid layout without using px.
Problem: In this jsFiddle http://jsfiddle.net/X3ZDy/73/ I have four equally proportioned boxes. They are designed to span the screen width and remain square. Contained within them are some sample square DIVs (40% x 40%). I'm struggling though to get a text label lbl horizontally and vertically centered within bbl.
All the examples I've seen (and tried) don't work as they require me to know the height of my label, or they use browser restricted table-layout tricks. I need to do this with all relative sizes as per the fiddle.
Can anyone assist? I need to this to work on ALL browsers with a pure CSS (no JS) solution. I'm astonished that it appears to be quite so tricky to vertically align text in a div. I don't mind if we use block or inline elements as the text label.
Please note that I'm NOT looking for a TABLE solution, this is a DIV & CSS puzzle that requires a working jsFiddle.
More:
Thanks all for your answers, but for future posters, note that (width == padding-bottom) is the magic that allows my DIVs to be square. It's key to a grid-layout system so I need to maintain that.
updated
It's pretty tricky working with relative sizes and no fixed heights, but I think I've finally found an answer to the problem (below).
I think I finally found an answer to the problem that works. The issue is that almost every other solution I've seen can't cope when the child size changes and none of the heights are known. I needed this to work for a responsive all % design where there are no fixed heights anywhere.
I stumbled across this SO answer Align vertically using CSS 3 which was my inspiration.
Firstly, using an all % design, you need a zero height wrapper element to act as a positioning placeholder within the parent element;
<body>
<div class="container">
<div class="divWrapper">
<div class="tx">This text will center align no matter how many lines there are</div>
</div>
</div>
</body>
My Container in this case is a simple box tile;
.container
{
margin:2%;
background-color:#888888;
width:30%;
padding-bottom:30%; /* relative size and position on page */
float: left;
position:relative; /* coord system stop */
top: 0px; /* IE? */
}
So nothing special about that except that it has no height which makes this general problem of centering elements tricky. It needs to be absolutely positioned so that we can uses positioning coordinates in the child elements (I think this may require a 'top' in IE).
Next, the wrapper which is absolutely positioned to exactly overlay the parent element and fill it out completely.
.divWrapper
{
position:absolute;
top:0px;
padding-top:50%; /* center the top of child elements vetically */
padding-bottom:50%;
height:0px;
}
The padding means that any child elements will start in exactly the middle of the parent element but this wrapper itself has no height and takes up no space on the page.
Nothing new yet.
Finally, the child element we want to center. The trick here to this was to have the child element slide up vertically based on it's own height. You can't use 50%, because that's 50% of the parent container not ourself. The deceptively simple answer is to use a transform. I can't believe I didn't spot this before;
.tx
{
position: relative;
background-color: transparent;
text-align: center; /* horizontal centering */
-webkit-transform: translateY(-50%); /* child now centers itself relative to the midline based on own contents */
-moz-transform: translateY(-50%);
-ms-transform: translateY(-50%);
-ms-filter: 'progid:DXImageTransform.Microsoft.Matrix(M11=0.5, M12=0, M21=0, M22=0.5, SizingMethod="auto expand")'; /*IE8 */
filter: progid:DXImageTransform.Microsoft.Matrix(M11=0.5, M12=0, M21=0, M22=0.5, SizingMethod='auto expand'); /*IE6, IE7*/
transform: translateY(-50%);
}
Here's the Fiddle
However, I haven't tested this on IE6+ so if somebody would like to verify my Matrix transform I'd appreciate it.
Update
It turns out that the wrapper isn't even needed. This is all you need to properly vertically center;
.tx
{
width:100%; // +1 to #RonM
position: absolute;
text-align: center;
padding-top:100%;
-webkit-transform: translateY(-50%); /* child now centers itself relative to the midline based on own contents */
-moz-transform: translateY(-50%);
-ms-transform: translateY(-50%);
-o-transform: translateY(-50%);
-ms-filter: 'progid:DXImageTransform.Microsoft.Matrix(Dx=0,Dy=0)'; /*IE8 */
filter: progid:DXImageTransform.Microsoft.Matrix(Dx=0,Dy=0); /*IE6, IE7*/
transform: translateY(-50%);
}
And the updated Fiddle
But still not working in IE6 yet - looking at those transforms, I don't think this can be done for that legacy without JavaScript.
The reality is, that the only tags in HTML that have native fluid vertical alignment are the table cells.
CSS does not have anything that would get you what you want. Not today.
If the requirements are:
1. Works with every browser
2. fluid height
3. vertical centering
4. no scripting
5. No TABLEs
6. You want the solution today, not in few years
You are left with 1 option:
1. Drop ONE of your requirements
Otherwise this "puzzle" is not completable. And this is the only complete acceptable answer to your request.
... if only I could get all the salaries for the wasted hours on this particular challenge :)
Don't self-abuse; let IE7 go... :) (According to this, not very many people are using it.)
I gave this a shot with two approaches, one uses display: table and the other uses line-height. Unfortunately, I don't have access to a PC, so they're only tested in Chrome 25.0.1365.1 canary, FF 18, and Safari 6.0 on Mac 10.8.1, iOS 6.0.1 Safari, and iOS Simulator 5.0 and 5.1 Safari.
The display: table approach has issues on iOS Simulator 5.0 and 5.1, the text isn't quite centered, vertically.
According to quirksmode, the display:table method should be compatitible with IE8 and up. Theorectically, the line-height method might be compatible with IE 6/7.
To create the centered box within each square, I set .box6 to position: relative and changed the .bc style to:
.bc {
position:absolute;
top: 30%;
bottom: 30%;
left: 30%;
right: 30%;
overflow: hidden;
}
Each approach creates a very tall container with a static height inside the .bc element. The exact value for the static height is arbitrary, it just needs to be taller than the content it will contain.
The display: table method changes the .bbl and .bbl .lbl styles to:
.bbl {
display: table;
height: 500px;
padding-top: 50%;
margin-top: -250px;
background-color: blanchedalmond;
width: 100%;
}
.bbl .lbl {
display: table-cell;
vertical-align: middle;
text-align:center;
}
For the line-height method, the HTML is:
<div class="bc">
<div id="line-h-outter">
<span id="line-h-inner">a lot more text than in the other blob. The quick brown fox jumped over the lazy dog</span>
</div>
</div>
CSS:
#line-h-outter {
line-height: 500px;
vertical-align: middle;
margin-top: -250px;
padding-top: 50%;
}
#line-h-inner {
display: inline-block;
line-height: normal;
vertical-align: middle;
text-align: center;
width: 100%;
}
http://jsfiddle.net/X3ZDy/93/
The title should be Centering in the Unknown ;-)
I updated your example using tables: http://jsfiddle.net/uWtqY/ and the text is align inside the box you described using tables, but you don't want this.
Added a table with like:
<table width="100%" height="100%"><tr><td>One line</td></tr> </table></div>
inside <div class="lbl">
Just for cross-browser support.
EDIT
After doing some research indeed it is really hard to v-align an element inside percentages.
Tried a lot of stuff but your code I am not sure if it fits the design of all of them. Well what I mean in other words is that you might first need to construct your vertical alignment and then try to play with percentages. From my experience in this field I learned that a good approach is start designing from the inside elements and then go out if complexity increases. So having percentages in everything might not be the best implementation (and it is not when coming to mobile devices).
EDIT 2
After consolidating with several of my work partners and really geeks on the area of HTML the answer was clear. Either you support < IE7 and you do that with a table or ghost elements or spans, either you use all of the tequniques that are described in several posts and you can have support for >=IE7 . Another option is to use specific structure for each browser.
The link that I think explains it as it is and has a nice title (basically is what you need):
-> Centering in the Unknown
Hope the best.
PS. Links for reference:
http://web.archive.org/web/20091017204329/http://www.zann-marketing.com/developer/20050518/vertically-centering-text-using-css.html
http://css-tricks.com/vertically-center-multi-lined-text/
http://www.jakpsatweb.cz/css/css-vertical-center-solution.html
Let me know if it helps
I updated the css to utilize a "spacer" class. It is placed before your "bc" div and inside the colored boxes. This gave me the effect I think you requested.
html:
<div class="rgCol boxCol box6" style="background-color:lightgray">
<div class="spacer"></div>
<div class="bc">
css
.spacer {width:100%;padding-bottom:30%;display:block; }
I bottom padded the spacer by 30% and then moved the absolute left position of your "bbl" div to 30% (from 2%). The blanchdelemond boxes retain their shape and size.
http://jsfiddle.net/X3ZDy/37/
Today I have stumbled upon similar problem - to both vertically and horizontally center child element of a square divs which have precentually set width (they are made sqare using the padding technique). I had to use it for images while maintaining aspect ratio, but changing the child into any target element would be simple.
For this situation no line-height, margin/padding or display:table-cell workaround is suitable. But there is a solution using margin: auto.
HTML:
<div class="squareContainer>
<div class="contentWrapper">
<img class="imagePreview" alt="Image preview" src="//URL.jpg">
</div>
</div>
CSS:
div.squareContainer {
position: relative;
box-sizing: border-box;
height: 0;
padding-bottom: 25%;
width: 25%;
}
div.contentWrapper {
position: absolute;
bottom: 0;
left: 0;
right: 0;
top: 0;
}
img.imagePreview {
display: block;
position: absolute;
bottom: 0;
left: 0;
right: 0;
top: 0;
margin: auto; /* This is the important line */
max-height: 90%;
max-width: 90%;
}
Helpful resources:
http://jsfiddle.net/mBBJM/1/
http://codepen.io/HugoGiraudel/pen/ucKEC
Hope that helps!
You can solve this trivially, without all the weirdness (perhaps someday they'll fix the CSS box model, but till then):
<table>
<tr>
<td width="50" height="50" align="center" valign="middle">text</td>
</tr>
</table>
That's all there is to it. Choose your width and height, drop it in a div and call it good.
The idea of never using tables is a very poor guideline, to the point of being self-abusive.
Do you mean like this?
<div class="mycontainer">
<div class="rgRow">
<div class="rgCol" style="background-color:pink">
<div class="boxCol">BOX1</div>
</div>
<div class="rgCol" style="background-color:lightgray">
<div class="boxCol">
<div class="boxLabel">a lot more text than in the other blob. The quick brown fox jumped over the lazy dog</div>
</div>
</div>
<div class="rgCol" style="background-color:maroon">
<div class="boxCol">
<div class="boxLabel">One liner</div>
</div>
</div>
<div class="rgCol" style="background-color:yellow">
<div class="boxCol">BOX4</div>
</div>
</div>
</div>
.mycontainer
{
background-color: #000000;
display: inline-table;
}
.rgRow
{
width: 100%;
display: table-row;
}
.rgCol
{
width: 25%;
height: 100%;
text-align: center;
vertical-align: middle;
display: table-cell;
}
.boxCol
{
display: inline-block;
width: 100%;
text-align: center;
vertical-align: middle;
}
.boxLabel
{
text-align: center;
vertical-align: middle;
background-color: blanchedalmond;
overflow: hidden;
margin: 2%;
width: 96%;
height: 96%;
}

Trying to set JScrollPane height to 100% without stretching container?

I have a middle container that takes up whatever vertical space is left on the screen. In it, I placed a Jquery scroller that is currently set to 200px:
.scroll-pane
{
width: 100%;
height: 200px;
overflow: auto;
}
.horizontal-only
{
height: auto;
max-height: 100%;
}
However, if I set .scroll-pane height to 100%, it just removes the scrollbar and stretches the whole page.
See JsFiddle here
How can I stop this? Thanks!
Here is my solution to this problem (jsfiddle). It uses markup like this:
<div id="top">...</div>
<div id="wrapper">
<div id="middle">...</div>
</div>
<div id="bottom">...</div>
The top and bottom divs are position absolutely at the top and bottom, with a width of 100%. The wrapper div has height: 100%, box-sizing: border-box, and top and bottom padding equal to the height of the top and bottom divs, respectively. This causes it to fill the viewport but have padding underneath the top and bottom divs. The middle div has a height of 100% so it fills the content box of the wrapper (i.e., 100% minus the top and bottom paddings). It has position: relative, which leaves you free to use height: 100% on both interior boxes.
Lastly, middleleft is positioned absolutely and middleright has a left margin equal to its width, which causes it to fill the remaining horizontal space.
height: 100% never works like you want it to. The CSS specifications dictate that it must equal the height of the browser window, or the closest parent block-level element with an absolute height specified. That means that this code will should not work as expected:
<!DOCTYPE html>
<html>
<head>
<title>Want the body to fill the page? Too bad!</title>
<style type="text/css">
html, body {
height: 100%;
}
.page {
padding-top: 50px;
box-sizing: border-box;
height: 100%;
}
.header {
margin-top: -50px;
height: 50px;
}
.body {
height: 100%;
background: gray;
}
</style>
</head>
<body>
<div class="page">
<div class="header">
<h1>Too bad!</h1>
</div>
<div class="body">
<p>Hello cruel world...</p>
</div>
</div>
</body>
</html>
However, that works fine in Chrome. Why? I can only assume that Google decided to specifically go against web standards because in this case, the standards make no sense. Why would I want something to be the exact height of the browser window? The only time is a <div> wrapping the whole page; in this case a simple "height is relative to the parent block" rule works just fine without breaking expectations elsewhere.
There is a way around this, though. At least, that's what I wanted to say before I tried this in Firefox too. Another way to get height: 100% (with some restrictions) is with position: absolute. However, it would seem that Firefox isn't respecting position: relative on a display: table-cell element - probably those pesky standards again. Here's the code for this technique anyway, if you are interested:
#wrapper > div > #middleleft {
position: relative;
}
.scroll-pane {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
So what can you do? Well, unfortunately, I don't yet know the answer to that. A kludgy solution would be to have Javascript set the height to an absolute pixel value, and attach an event to window resizing in order to update that height. I'll get back to you if I find a better way.
I'm not sure exactly what your trying to do, but another method would be to set body height to 100%, then set scrollpane to "height: auto". Then for the "top" and "bottom" div's used fixed positioning, plus margin equal to top/bottom height.
body {
height: 100%;
}
.top {
position: fixed;
top: 0;
height: 100px;
}
.middle {
height: auto;
margin: 100px auto;
}
.bottom {
position: fixed;
bottom: 0;
height: 100px;
}
<div class="top">content</div>
<div class="middle">content</div>
<div class="bottom">content</div>
Try that...

Background image centered and div elements position based on percentage relative to main bg image

I have a CSS background image that will stay centered no matter what the browser size is. The image used does not stretch the entire width of the browser. This being the case, I need the divs I have also placed in the CSS with background images and links to maintain their position relative to the background image that stays centered no matter what the browser size is.
I have dabbled around with.
position:relative;
but it cascades all the elements and doesn't allow specific positioning that I am looking for. Here is the code I am working with. I appreciate any insight to my newb question, and look forward to learning how this behaves better.
When this code is viewed on different sized browsers, with a background image that does not span the entire width, the elements move around because they are set to percentage. I need them to stay where they are but remain centered with the background. I am not sure how to write this in CSS and have been struggling with it for some time. Thankyou for any guidance on this specific issue.
body {
background:#000 url(bg.jpg) no-repeat center 0;
}
#logo {
margin: 0px 11%;
padding: 0;
position:absolute;
}
try grouping elements you want to put next to it together inside a div ~say container~ and set the background to the div.
Then set the div ~container~ position to relative and center it.
Then align other elements using position absolute and top bottom left right property wrt the ~container~div.
here is the code for it
<div id="container">
<div id="element1"></div>
<div id="element1"></div>
</div>
<style type="text/css">
#container {
background:#000 url(bg.jpg) no-repeat center 0;
width: 800px; height: 400px
position: relative;
top: 50%; left: 50%;
margin-top: -200px; margin-left: -400px }
#element1 {
position: absolute;
top: -30px; left: -20px;}
#element2 {
position: absolute;
top: 410px; left: 820px;}
</style>

Resources