Best Way to Centre Dynamic Div in Middle of Page - javascript

I know this sort of thing has been asked a lot but I want to be able to centre a div in the middle of the page and have it always stay in the middle of the page no matter how wide or tall it gets.
I'm guessing that it would be best to use some javascript to work out how wide the element will be and then half that amount to take away from the margin.
To clear things up, this sort of thing:
.myDivHere {
position: absolute;
left: 50%;
top: 50%;
text-align: center;
width: 20%;
height: 20%;
margin-left: -273px; /*half width set by js script*/
margin-top: -132px; /*half height set by js script*/
}
I have set the width and height to be 20% as I want this div to be able to retain its size relative to the browser window (for mobile support and such). Any ideas?

Unless I'm missing something you can forgo the JavaScript and use plain CSS:
div {
position:absolute;
background:red;
width:20%;
height:20%;
top:0;
bottom:0;
left:0;
right:0;
margin:auto;
}
jsFiddle example

Here is you go.
It should be noted that this answer is more about concepts than giving you the answer outright.
Now, you see the 'div#b' section of the CSS? To keep everything in the center, simply write a script that keeps the margin-top value -50% of the height. And that's it!
Example:
(currently) height = 60, margin-top = -30px (changed for height = 100) height = 100, margin-top = -50px
div#a
{
width: 300px;
height: 300px;
border-width:1px;
border-style: solid;
/* important stuff below */
display: inline-block;
}
div#b
{
width: 60px;
height: 60px;
background-color: red;
/* important stuff below */
position: relative;
margin: -30px auto 0 auto;
top: 50%;
}

Here's a codepen:
Check it out.
Most of your styles aren't necessary, and javascript is definitely unnecessary. The key to vertical centering is display: table. It requires some nesting, so I altered your structure as well.

In jQuery you can use .width() and .height() methods as they returns computed width in pixels, not in percentage + you will need to listen window resize event. For example like this:
$(function() {
function updateDivPosition() {
var myWidth = $( '.myDivHere' ).width()
, myHeight = $( '.myDivHere' ).height();
$( '.myDivHere' ).css( {
marginLeft: -( parseInt( myWidth, 10 ) / 2 ) + 'px',
marginTop: -( parseInt( myHeight, 10 ) / 2 ) + 'px'
});
}
updateDivPosition(); // first time set correct position on onload
$( window ).resize( updateDivPosition ); // update on window resize
});
jsFiddle demo

Related

Maintain aspect ratio of a video when resizing the browser

I'm working on a Video editing tool, and I need to maintain the 16:9 aspect ratio of the video when resizing the screen horizontally and vertically. So far I got it to work as expected when resizing horizontally, and when resizing down vertically, but can't get it to work when sizing up vertically. The Javascript code I used to calculate the height of the video and resize it is below (notice how the else clause is empty because that's where the code should go):
const calculateHeight = () => {
// Get the other elements on the page
const header = document.querySelector('.main-navigation');
const meshTopBar = document.querySelector('.mesh__top-bar');
const footer = document.querySelector('.mesh__bottom-bar');
// Get the section to apply the window height to it
const mainSection = document.querySelector('.insert-level-container');
// Get the video elements
const editor = document.querySelector('.mesh__insert-editor-container');
const video = document.querySelector('.mesh__insert-editor-video-container');
// Apply the height to the main section by calculating the window height minus the other elements' height
if(mainSection !== null) {
mainSection.style.height = (window.innerHeight - header.offsetHeight - meshTopBar.offsetHeight - footer.offsetHeight) + 'px';
}
// This should be the ideal height for the video
video.style.minHeight = ((video.offsetWidth * 9) / 16) + 'px';
// If the video height is bigger than the section height (calculated above), then resize it
if(video.offsetHeight + 115 > mainSection.offsetHeight) {
video.style.minHeight = video.offsetHeight - 1 + 'px';
editor.style.maxWidth = video.offsetHeight * 16 / 9 + 'px';
} else {
// This is where the logic for the vertical resizing should go
}
}
The relevant CSS for these items is:
.mesh__insert-editor-container {
margin-left: auto;
margin-right: auto;
}
.mesh__insert-editor-video-container {
position: relative;
width: 100%:
}
And the HTML:
<section class="mesh__insert-editor-container flex__one flex-container flex-column horizontally-left-aligned" id="video-main-container">
<div class="mesh__insert-editor-video-container flex-container horizontally-right-aligned flex-wrap">
<video class="mesh__insert-editor-video-placeholder"></video>
</div>
</section>
All this code is:
Get the height of all the elements on the page, sum them and calculate the main section height by subtracting that height;
If the video height gets bigger than the section height, I reduce its height by -1px each time the window gets resized, and calculate the new width.
All the above code is giving me this result, which works great for most scenarios, but I need the video to size up when the condition on the if statement is not met. Everything I tried inside the else statement gets "jumpy".
Any better alternatives to solve this would be much appreciated. Thanks all!
The CSS aspect ratio trick might be a good solution: https://css-tricks.com/aspect-ratio-boxes/
The approach takes advantage of a quirk in CSS where padding based on a percentage value will be relative to the element's width. Create a container using this trick, the important bit is this line:
padding-top: calc(9/16 * 100%);
The value is calculating the correct height based on the aspect ratio you want (9 tall over 16 wide in this case) and generating it relative to the width of the element by multiplying by 100%.
With the container maintaining aspect ratio, just place the content inside an absolute positioned inner div and you should be good. This solution is fully responsive at that point.
* { box-sizing: border-box }
.outer-max-width {
max-width: 960px;
margin: 0 auto;
}
.aspect-ratio-box {
width: 100%;
padding-top: calc(9/16 * 100%);
position: relative;
border: 2px solid red; /* for demo visibility, remove */
}
.aspect-ratio-box-content {
position: absolute;
width: 100%;
top: 0;
left: 0;
border: 2px solid blue; /* for demo visibility, remove */
}
.video-placeholder {
display: block;
width: 100%;
height: auto;
}
<div class="outer-max-width">
<div class="aspect-ratio-box">
<div class="aspect-ratio-box-content">
<img class="video-placeholder" src="https://placeimg.com/640/360/nature" />
</div>
</div>
</div>
Got it to work! I used this amazing CSS-only solution: https://codepen.io/EightArmsHQ/pen/BvNzrm similar to BugsArePeopleToo's suggestion, from eightarmshq:
.content{
position: absolute;
top: 0;
bottom: 0;
width: 100%;
height: 100%;
background: #555;
box-shadow: inset 1vh 1vh 10vh 0 rgba(0,0,0,0.5);
display: flex;
box-sizing: border-box;
border: 25px solid #cecece;
}

why is child element's width changing when parent's width changes?

I am trying to create a tooltip element that has a min width of 50px and a max width of 200px. I place the tooltip element inside another element so that I can easily control when the tooltip appears or disappears when there is a hover event on the parent.
The problem that I have is that the tooltip element's width appears to be controlled by the parent's width even though I specified that the child(tooltip) has an absolute position.
let p = document.getElementById( 'parent' );
let b = true;
setInterval( ()=> {
b = !b;
let w = 10;
if( b ) {
w = 300;
}
p.style.width = `${w}px`
}, 5000 );
#parent {
background-color: cyan;
width: 100px;
height: 25px;
position: relative;
transition: width 2s;
}
#tooltip {
position: absolute;
top: calc( 100% + 5px );
left: 5px;
min-width: 50px;
max-width: 200px;
background-color: yellow;
padding: 5px;
border: 1px solid black;
}
<div id="parent">
<div id="tooltip">
My long tooltip text that wraps to multiple lines as needed.
</div>
</div>
I would like the tooltip (yellow div) to keep it's size at 200px in this example, but we can see that when the parent changes width, the tooltip width also changes. Why?
Is there a way to fix this problem?
Clarification: In this example: https://codepen.io/anon/pen/ePPWER we see that the tooltip text looks nice on one line. I don't want the tooltip's div to change its width when the parent changes width, because it forces the tooltip text to wrap onto 2 lines which is undesirable.
If we check the specification related to the width of absolutely positioned element we can read this:
'width' and 'right' are 'auto' and 'left' is not 'auto', then the width is shrink-to-fit . Then solve for 'right'
So in your case the width of your element is shrink to fit:
Calculation of the shrink-to-fit width is similar to calculating the
width of a table cell using the automatic table layout algorithm.
Roughly: calculate the preferred width by formatting the content
without breaking lines other than where explicit line breaks occur,
and also calculate the preferred minimum width, e.g., by trying all
possible line breaks. CSS 2.1 does not define the exact algorithm.
Thirdly, calculate the available width: this is found by solving for
'width' after setting 'left' (in case 1) or 'right' (in case 3) to 0.
Then the shrink-to-fit width is: min(max(preferred minimum width,
available width), preferred width).
To make it easy, and without considering the min/max-width, the width of your element will try to fit the content without exceding the width of its parent container (containing block). By adding min/max-width you simply add more constraint.
One idea of fix it to remove positon:relative from the parent element so that it's no more the containing block of the position:absolute element (it will be the initial containing block which is wide enough to avoid the available width constraint).
Then use margin instead of top/left to control the position:
let p = document.getElementById( 'parent' );
let b = true;
setInterval( ()=> {
b = !b;
let w = 10;
if( b ) {
w = 300;
}
p.style.width = `${w}px`
}, 5000 );
#parent {
background-color: cyan;
width: 100px;
height: 25px;
transition: width 2s;
}
#tooltip {
position: absolute;
margin-top: 30px;
min-width: 50px;
max-width: 200px;
background-color: yellow;
padding: 5px;
border: 1px solid black;
}
<div id="parent">
<div id="tooltip">
My long tooltip text that wraps to multiple lines as needed.
</div>
</div>
ID Tooltip is being used under Parent. When parent's width changes, it also suggest that tooltip's total width is changed. Since you have used mix-width and max-width it will expand till it reaches max-width. If you want it to be fixed then simple use width.
It is because the .parent has a position: relative. This will keep all children (position: absolute included) as confined by the parent div.
Not sure if this will work for you because it is pulling the tooltip out of the parent and making it's own with span wrapping the text. Alternatively, you'll need to change the parent from being relative otherwise it'll continually affect the child.
let p = document.getElementById('parent');
let b = true;
setInterval(() => {
b = !b;
let w = 10;
if (b) {
w = 300;
}
p.style.width = `${w}px`
}, 5000);
#parent {
background-color: cyan;
width: 100px;
height: 25px;
transition: width 2s;
position: relative;
}
#root {
position: relative;
}
#tooltip {
width: 100%;
}
#tooltip span {
position: absolute;
top: calc( 100% + 5px);
left: 5px;
min-width: 50px;
max-width: 200px;
background-color: yellow;
padding: 5px;
border: 1px solid black;
}
<div id="root">
<div id="parent"></div>
<div id="tooltip">
<span>My long tooltip text that wraps to multiple lines as needed.</span>
</div>
</div>

How to keep div in center-height when I resize the browser window?

I am trying to center in height a div, however it does not work when I resize the browser screen.
How to edit this to achieve the adjustable margin-top on resize?
Thank you
<script>
var h = $(window).height();
var parentHeight = h;
var childHeight = $('#a-middle').height();
$('#a-middle').css('margin-top', (parentHeight - childHeight) /2);
</script>
Edit:
The answer should be in js since flexbox won't work on IE-9
you should stick to a CSS solution though, there are several way to achive this
.alignVertical {
position:relative;
display:inline-block;
top:50%;
transform:translateY(-50%);
}
jsfiddle: https://jsfiddle.net/jorjmt70/
or using flexbox
.parent {
display:flex;
height:100vh;
background-color:red;
justify-content:center;
align-items:center;
flex-direction:column;
}
jsfiddle: https://jsfiddle.net/mdh9h876/
if you want to use flex box use autoprefixer to get deeper browsersupport:
https://github.com/postcss/autoprefixer
Although you can easily do this with pure CSS, your bounty stated that you want a JS answer.
If you are interested in a pure CSS answer, see this answer that has multiple different methods on how to center elements vertically/horizontally.
You could simplify your jQuery to the following:
$('#a-middle').css('margin-top', function () {
return ($(window).height() - $(this).height()) / 2
});
Then you could just place this within a resize event listener and chain the .resize() method in order to trigger the event initially when the browser loads.
Example Here
$(window).on('resize', function () {
$('#a-middle').css('margin-top', function () {
return ($(window).height() - $(this).height()) / 2
});
}).resize();
JavaScript equivalent (without jQuery):
Example Here
var verticalCentering = function () {
var el = document.querySelector('#a-middle');
el.style.marginTop = (window.innerHeight - el.offsetHeight) / 2 + 'px';
}
window.addEventListener('resize', verticalCentering);
verticalCentering();
For a div called 'center-me':
$(document).ready(centerDiv);
$(window).resize(centerDiv);
function centerDiv() {
var winHeight = $(document).innerHeight(),
divHeight = $('.center-me').height();
$('.center-me').css('marginTop', (winHeight - divHeight) / 2 );
}
You need to call it when the document is ready, to get it centered in the first place, then on resize-event, to keep it centered.
Here is the fiddle for it: Fiddle
A CSS solution could do the trick for you.
div.center {
height: 100px;
width: 300px;
top: 50%;
left: 50%;
margin-top: -50px;
margin-left: -150px;
position: absolute;
background-color: red;
}
<div class="center">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</div>
This CSS code work fine in IE8+, Firefox and Chrome.
But you must know the sizes of the DIV that you want to adjust correctly. If the height and width are dynamic, you just have to update the style accordingly with JavaScript. Don't forget to apply the class center in JS on need to your DIV.
Explanations :
margin-top : - height / 2 because top : 50% only centered vertically the top of the DIV.
margin-left : - width / 2 because left : 50% only centered horizontally the left of the DIV.
position : absolute so that the DIV can center over all the page.
This can be achieved using simple CSS with deep browser support back to IE8.
html, body {
height: 100%;
}
.parent {
display: table;
table-layout: fixed;
width: 100%;
height: 100%;
}
.child {
display: table-cell;
vertical-align: middle;
text-align: center;
background: red;
}
<div class="parent">
<div class="child">This is always centered.</div>
</div>
Using table-layout makes it simple: the child can be vertically aligned (top, middle, bottom) and will take up all the available height. You're not resorting to JavaScript, CSS with patchy support or having to hard-code any figures, it should just work.
Depending on the specifics of what you're looking to do, flexbox or - as a last resort - JavaScript might be required, but for most cases display: table-cell is your friend.
That said, if it's acceptable for older browsers to get a different layout, just use #Victor's answer: this is what flexbox is for.
To make a div always stay at the center of the screen, the properties you could use are top and left attributes after setting the position attribute to absolute. However you will need to set these properties dynamically when the browser is resized. This can be done using the JQuery method - resize().
/*css code*/
.div{
position:absolute;
top:100px;
left:50px;
background:black;
}
/*JS Code*/
function keep_div_centered()
{
window_height = $(window).height();
window_width = $(window).width();
obj_height = $('.keepincenter').height();
obj_width = $('.keepincenter').width();
$('.keepincenter').css('top',(window_height/2)-(obj_height/2)).css('left',(window_width/2)-(obj_width/2))
}
keep_div_centered();
$(window).resize(function(){
keep_div_centered();
})
/* HTML Code */
<div class="keepincenter"></div>
Link to the fiddle - http://jsfiddle.net/y0937t06/
$(window).resize(function () {
var h = $(document).height();
var parentHeight = h;
var childHeight = $('#imagegallery').height();
$('#imagegallery').css('margin-top', (parentHeight - childHeight) / 2);
});
For me, this is the holy grail of CSS :)
The most reliable method I found is setting the container element as follows:
display: -webkit-flex;
-webkit-justify-content: center; /* horizontal */
-webkit-align-items: center; /* vertical */
It is simple and has no prerequisites on any other CSS properties.
The fiddle below places content 30px above vertical center:
#container {
width: 500px;
height: 300px;
background-color: red;
display: -webkit-flex;
-webkit-justify-content: center;
-webkit-align-items: center;
}
#content {
background-color: green;
margin-bottom: 30px;
}
<div id="container">
<span id="content">Content</span>
</div>
Handle window_resize event of the current window and try putting above code there.
It should give you expectd functionality.
This approach is very useful when you want to center both vertically and horizontally an absolute position div. It work also on IE8
You need to set the both outer and inner divs as
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
margin:auto;
margin:auto it's fundamental to center divs in this case.
You could also set the height and width of the .in div and still you would see it centered vertically and centered also when you resize the browser.
* {
margin: 0;
padding: 0;
}
html, body {
position: relative;
height: 100%;
width: 100%;
}
.in, .out {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
margin:auto;
}
.in {
background-color: red;
height: 50%;
width:50%;
}
.out {
background-color: blue;
}
EXAMPLE 1 JSFIDDLE height, width: in percentages: http://jsfiddle.net/a_incarnati/1o5zzcgh/3/
EXAMPLE 2 - JSFIDDLE fixed height, fixed width
http://jsfiddle.net/a_incarnati/1o5zzcgh/4/
Give display: table-cell; to the parent and align the contents vertically using vertical-align and give the padding to adjust the necessary spacing from top.
.child{
display:table-cell;
vertical-align:top;
padding-top: 50px;
}
This will keep the margin uniform throughout.
use css
first give a height to your element.
#a-middle {
height: 20px;
position: fixed;
top: calc(50% - 10px);
left: 0;
}
or use js
$(function(){
$('#a-middle').each(function(){
var t = $(window).height()/2 - $(this).outerHeight()/2;
$(this).css({top: t + "px"});
});
});
$(window).resize(function(){
$('#a-middle').each(function(){
var t = $(window).height()/2 - $(this).outerHeight()/2;
$(this).css({top: t + "px"});
});
});
The problem with the previous solutions is that you won't be able to center the div, if he's larger than the available vertical size.
If you want your div to take 50% of the page you can use the CSS vertical height based unit:
.mydiv {
height: 50vh;
top: 50%;
left: 50%;
position: fixed;
width: 50vh;
margin-top: -25vh;
margin-left:-25vh;
border: solid black 1px;
}
So your DIV will not only be centered but also maintain its ratio.
Play with margin-left and margin-top of that div, using the width and height of the window and div.
$(function () {
makeDivCenter();
$(window).resize(function () {
makeDivCenter();
});
});
function makeDivCenter() {
var windowWidth = $(window).width();
var divWidth = $(".center").width();
var windowHeight = $(window).height();
var divHeight = $(".center").height();
$(".center").css({
'margin-left': (windowWidth / 2) - (divWidth / 2) + "px",
'margin-top': (windowHeight / 2) - (divHeight / 2) + "px"
});
}
Here is jsfiddle for your reference https://jsfiddle.net/fnuud7g6/

Switch div from fixed to absolute at bottom of browser

Im trying to add a footer at the bottom of this content that doesn't overlay the content but moves it up.
The only way I can see it working would be something like, when browser is at the bottom remove 'fixed' class on the left red '#work'.
js fiddle DEMO
Updated js fiddle DEMO
HTML
<div id="header-block">
Header-block, this sits here in the background
</div>
<div id="content">
<div id="work">
This content should be fixed when at the top
</div>
<div id="description">
This content should scroll -
</div>
</div><!-- end content -->
<div id="footer">
This should appear at the bottom
</div>
CSS
body {
margin: 0px;
padding: 0px;
}
#header-block {
background: green;
width: 100%;
position: fixed;
z-index: 1;
height: 300px;
top: 0;
}
#content {
margin-top: 300px;
width: 100%;
position: relative;
z-index: 2;
}
#work {
background: red;
width: 50%;
height: 100vh;
float: left;
position: absolute;
}
#description {
background: blue;
width: 50%;
height: 1200px;
float: right;
font-size: 30px;
}
#footer {
background: black;
width: 100%;
height: 100px;
position: absolute;
z-index: 3;
bottom: 0;
}
If I understand your question correct, this should do the trick (although it depends very much on JavaScript unfortunately).
// Fix work column on scroll
contentStart = $("#content").offset().top ;
contentSize = $("#content").height() ;
window.onscroll = function(){
if( window.XMLHttpRequest ) {
var position=window.pageYOffset;
// calculate the position of the footer and the actual seen window
var docViewTop = $(window).scrollTop();
var docViewBottom = docViewTop + $(window).height();
var elemTop = $("#footer").offset().top;
if ( position > 300 && !(docViewBottom >= elemTop)) {
$('#work').css({'position':'fixed', 'top':'0', 'height':'100vh'});
} else {
// if the footer is visible on the screen
if(docViewBottom >= elemTop) {
$('#work').css({ 'top': 0 - (docViewBottom - elemTop) }); // scroll the #main div relative to the footer
} else {
$('#work').css({'position':'relative', 'top': 'auto'}) ;
}
}
}
}
For further informations about the calculations, perhaps this question on stackoverflow is useful.
Edit: Andrew Haining posted his answer in between of my answer, perhaps give his link a try and maybe it's a better (more proper) solution. Unfortunately I haven't actualised this page when I was testing your code in JSFiddle and I didn't see his answer.
If you want to use my script, make sure you can test it with different resolutions. It works just fine for my resolution in JSFiddle, I didn't test any other.
I'm not 100% sure what you want, but if you remove the position: absolute and the bottom: 0 from the footer, and put a div with class='clearboth' above the footer, it seems to do what you need.
CSS
.clearboth {
clear: both;
}
This is a drawing of what I see on your fiddle;
Do you want the red and the blue to always be touching the black?
I don't see the red overlying the black
You should use jQuery to add a class containing the position:fixed value when the scroll position of the page is less than the inline position of the #work div. Once it scrolls past the position, remove the class and have the element fall back in line.
You can achieve this using the following jQuery methods.. .scrollTop() .offset().top() and $(window).height().
This tutorial will give you an understanding of what you need to do to achieve the necessary results, you will just have to change the calculation slightly using $(window).height(), $('#footer').height() and a few other changes to get what you desire.
Based on the question you asked i think this is what you mean. The red div should be fixed when it gets to the top but be absolute when it is below the top for scrolling and the black footer should be below the red while scrolling, check this code i have done for you. just add this jquery script and run it.
<script type="text/javascript" src="js/jquery.js"></script>
<script>
$(document).ready(function() {
$(window).scroll(function () {
console.log($(window).scrollTop());
if ($(window).scrollTop() >= 322) {
$('#footer').css("z-index","1");
$('#work').css(
{
"background": "red",
"width": '50%',
'height': '100vh',
'float': 'left',
'position': 'fixed',
'top': '0'
});
}
if ($(window).scrollTop() <= 322)
{
$('#work').css(
{
"background": "red",
"width": "50%",
"height": "100vh",
"float": "left",
"position": "absolute"
});
};
});
});
</script>
If not exactly a parallax, this is somewhat close to how parallax works, containers moving at different speeds, and some containers sitting fixed or scrolling when they attain a particular top/bottom offset in the viewport.
There's plugin that can do it. Skrollr
You can use Skrollr along with skrollrcss, and it'll make sure how the containers take position on screen based on scrolltop of the window and the container specifically.

How do you vertically align the body tag of an HTML document?

I have a webpage that is horizontally centered but is rather short - it only takes up half the vertical page. I want it to be centered. How can I center the tag vertically? I cannot have a static height, so that is not an option. if CSS is not powerful enough, can I use Javascript to accomplish this? Thanks!
Two primary ways, neither of which is especially perfect, but widely used:
1) if your content really is a fixed, known height, then you CSS position it with
position: absolute;
top: 50%;
margin-top: here, set a pixel value that's equal to: -1 * (content height / 2)
2) If you don't care if it works the same way in IE7 and below, set CSS as follows:
html { display: table; }
body { display: table-cell; vertical-align: middle; }
If you don't mind adding non-semantic markup, you can do this:
html:
<div class="pusher"></div>
<div class="center"></div>
CSS:
html, body {
height: 100%;
}
.pusher {
height: 100%;
margin-bottom: -50%;
}
.center {
background: green;
width: 400px;
height: 200px;
margin: 0 auto;
}
http://jsfiddle.net/Jsqqk/
If you do care about semantic markup, and have to support older browsers, then you'll have to resort to JavaScript for this. Here's one solution using jQuery:
var $window = $(window),
$container = $('#container');
$window.resize(function(){
$container.css('margin-top',
Math.max(($window.height() / 2) - ($container.height() / 2), 0)
);
}).resize();
And here's the fiddle: http://jsfiddle.net/dw3rc/
I've often done this with setting height:50% and padding-top:25% but that's not always suitable.
This page identifies a different technique that might work:
http://www.jakpsatweb.cz/css/css-vertical-center-solution.html

Categories

Resources