I'm trying to center a pargraph below a div (could be a square image for the matter). I understand that the easiest way to do it is to contain both the div and the text below it in a single container and use text-align, but in this instance I have a limitation where I cannot let the small image be contained in a container wider than that image.
Without centering the text it looks like this:
My code:
HTML:
<div class="block"></div>
<p class="label">This text is a bit long</p>
CSS:
body {
padding: 5rem;
}
.block {
background-color: blue;
width: 80px;
height: 80px
}
.label {
}
Codepen:
https://codepen.io/omerh3/pen/oNqVjvV
The reason why I cannot let the image be in a container is that I'm using ReactFlow where the handles should connect to the sides of the image without a gap. If I put the image and the text inside a div, the div will take the width of the text and thus it will naturally be wider than the image.
I tried centering the text below the image with absolute positioning, but with different paragraphs sizes, it won't be persistent in the center. Is there a away to achieve this without inserting the image/square and the text inside one div?
One last thing: the width of the image if constant, for example 100px
one way to do this is to get the coordinates of your two elements and then add margin-left: to adjust the position of the span
let divOffsets = document.getElementById('a').getBoundingClientRect();
let divRight = divOffsets.right;
let divLeft = divOffsets.left;
console.log(divLeft,divRight)
let spanOffsets = document.getElementById('b').getBoundingClientRect();
let spanRight = spanOffsets.right;
let spanLeft = spanOffsets.left;
console.log(spanLeft,spanRight)
let divCenter = divLeft + divRight / 2
console.log(divCenter)
let offset = divCenter - (spanLeft + spanRight / 2)
offset = offset + "px"
document.getElementById('b').style.marginLeft = offset;
body {
padding: 5rem;
border:solid 1px red;
position:relative;
}
.block {
background-color: blue;
width: 80px;
height: 80px;
}
span{
position:absolute;
}
<div id = 'a'class="block"></div>
<span id = 'b' >1234</span>
Do you mean something like this??
body {
padding: 5rem;
}
.block {
background-color: blue;
width: 80px;
height: 80px;
margin:0 auto;
}
p.label {text-align: center}
<div class="block"></div>
<p class="label">This text is a bit long</p>
I am trying to make a container that holds some text and images, and starts out at a certain size, say 48px. Upon clicking I want the container to grow to fit the contents, and on a second click reshrink down to 48px. The main issue is I don't want to set the height for the full size container, I would like the container to automatically resize to fit the content.
I have figured out how to start the blog at full size, shrink and regrow, but I can't figure out a way to have it start small, grow, and shrink again.
const hoistingId = document.getElementById('hoisting')
function enlargeBlogItem() {
if(hoistingId.style.height===''){
hoistingId.style.height = '3rem';
} else {
hoistingId.style.height = '';
}
}
hoistingId.addEventListener('click', enlargeBlogItem)
You can use overflow: hidden; on the parent element to ensure that the child elements are inside the parent and not overlapping and then use a JavaScript function to handle the size changes. Attribute attr-small is used to store the original value of height. By removing the height attribute from the style of the parent it will default to wrapping the children.
function toggleSize(el){
const originalSize = el.getAttribute('attr-small');
if(el.style.height === originalSize) {
el.style.removeProperty('height');
} else {
el.style.height = originalSize;
}
}
#container {
border: 1px solid;
width: 200px;
overflow: hidden;
}
#container:hover {
cursor: pointer;
}
.foo {
width: 90px;
height: 90px;
background-color: red;
display: inline-block;
margin-left: 5px;
margin-top: 5px;
}
<div id='container' onclick='toggleSize(this)' attr-small='48px' style='height:48px;'>
<div class='foo'></div>
<div class='foo'></div>
<div class='foo'></div>
<div class='foo'></div>
<div class='foo'></div>
<div class='foo'></div>
</div>
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;
}
I know we can use calc when lengths are defined:
flex-basis: calc(33.33% - 60px);
left: calc(50% - 25px);
height: calc(100em/5);
But what if a length is variable?
height: calc(100% - <<header with variable height>>);
OR
width: calc(100% - 50px - <<box with variable width>>);
Is there a standard way to do this in CSS?
I know the overall task is possible with flexbox and tables, but I'm wondering if CSS offers a simpler method. Flexbox, tables and simple Javascript are acceptable alternatives.
height demo
width demo
You can use CSS tables:
.wrapper {
display: table;
width: 100%;
margin: 15px 0;
}
.horizontal.wrapper > div {
display: table-cell;
white-space: nowrap; /* Prevent line wrapping */
border: 1px solid;
}
.left { width: 100px } /* Minimum width of 100px */
.center { width: 0; } /* Width given by contents */
.vertical.wrapper { height: 200px; }
.vertical.wrapper > div {
display: table-row;
}
.vertical.wrapper > div > span {
display: table-cell;
border: 1px solid;
}
.top { height: 100px; } /* Minimum heigth of 100px */
.middle { height: 0; } /* Height given by content */
.bottom { height: 100%; } /* As tall as possible */
<div class="horizontal wrapper">
<div class="left">100px wide</div>
<div class="center">Auto width, given by contents</div>
<div class="right">Remaining space</div>
</div>
<div class="vertical wrapper">
<div class="top"><span>100px tall</span></div>
<div class="middle"><span>Auto height, given by contents</span></div>
<div class="bottom"><span>Remaining space</span></div>
</div>
The horizontal case can also be achieved with floats:
#wrapper, .right { overflow: hidden; } /* Establish BFC */
#wrapper > div { border: 1px solid; }
.left, .middle { float: left; }
.left { width: 100px }
<div id="wrapper">
<div class="left">100px</div>
<div class="middle">Auto width, given by contents</div>
<div class="right">Remaining space</div>
</div>
Flexbox can do that.
Support is IE10 and up.
JSfiddle Demo
* {
margin: 0;
padding: 0;
}
html,
body {
height: 100%;
}
#container {
height: 100%;
display: flex;
flex-direction: column;
}
#top {
background-color: lightgreen;
}
#bottom {
background-color: lightblue;
flex: 1;
}
<div id="container">
<div id="top">green box variable height</div>
<div id="bottom">blue box no longer overflows browser window</div>
</div>
I'm looking for something simple and portable. In the same way a CSS
property can be easily applied across documents, I'm looking for
something similar in terms of ease-of-application for this function.
... isolated fix is preferred.
Horizontal:
This can be achieved using CSS only. As you do not prefer a flex layout solution, the next best bet would be a table layout.
A simple CSS snippet which you could drop into your project (and be done with) would look like this:
div.flexh {
display: table; box-sizing: border-box; padding: 0; margin: 0;
}
div.flexh > div {
display: table-cell; width: auto;
box-sizing: border-box; vertical-align: middle;
}
div.flexh > div:first-child {
/* Override your custom styling below */
min-width: 75px; width: 75px; max-width: 75px;
}
div.flexh > div:last-child { width: 100%; }
You can then add your site-specific styling to this base CSS as per site requirements. Like, nowrap etc.
Two apparent advantages of this solution are:
You do not need to change your markup and also do not need to decorate all children with classes. Just apply the class flexh to your parent div and that would be it.
Minimal Markup Required:
<div class="flexh">
<div>...</div>
<div>...</div>
<div>...</div>
</div>
You are not limited to just three columns. You could have as many columns as need be. The first one will have fixed width, the last one will be flexible, and all the columns in-between would get content-based widths.
Demo Fiddle: http://jsfiddle.net/abhitalks/qqq4mq23/
Demo Snippet:
div.flexh {
display: table; box-sizing: border-box; padding: 0; margin: 0;
/* Override your custom styling below */
width: 80%; border: 2px solid black;
border-right: 2px dashed black;
font-size: 1em;
}
div.flexh > div {
display: table-cell; width: auto;
box-sizing: border-box; vertical-align: middle;
/* Override your custom styling below */
background-color: lightgreen; border: 1px solid #ddd;
padding: 15px 5px;
}
div.flexh > div:first-child {
/* Override your custom styling below */
min-width: 75px; width: 75px; max-width: 75px;
background-color: orange;
}
div.flexh > div:last-child {
width: 100%;
/* Override your custom styling below */
background: skyblue;
}
<div class="flexh">
<div>75px Fixed Width</div>
<div>Variable Content Width</div>
<div>Flexible Remaining Width</div>
</div>
<hr/>
<div class="flexh">
<div>75px Fixed Width</div>
<div><img src='//placehold.it/128x48/66c' /></div>
<div>Flexible Remaining Width</div>
</div>
<hr/>
<div class="flexh">
<div>75px Fixed Width</div>
<div>Variable TextWidth</div>
<div>
<img src='//placehold.it/128x48/66c' />
<p>Variable ContentWidth</p>
</div>
<div>Flexible Remaining Width</div>
</div>
Vertical:
This is a bit tricky to achieve without flex layout. A table layout would not work here mainly because, the table-row would not keep a fixed height as required by your use-case. The height on a table-row or table-cell is only an indicative of the minimum height required. If the space is constrained, or the content exceeds the available space, then the cell or row will increase its height depending on the content.
As per the specs here: http://www.w3.org/TR/CSS21/tables.html#height-layout
The height of a 'table-row' element's box is calculated once the user
agent has all the cells in the row available: it is the maximum of the
row's computed 'height', the computed 'height' of each cell in the
row, and the minimum height (MIN) required by the cells...
...the height of a cell box is the minimum height required by the
content
This effect can be seen here: http://jsfiddle.net/abhitalks/6eropud3/
(Resize the window pane and you will see that the first row will increase in height as the content cannot be fit into the specified height, hence defeating the purpose)
Therefore, you can restrict the height indirectly either using inner markup like a div element, or let go of the table-layout and calculate the height for the flexible one. In your use-case, you prefer not to change the markup, hence I am not proposing an inner markup.
The best-bet here would be to use the time-tested model of plain block-level divs with the height of the flexible one to be calculated. As you have already discovered that it is not possible with CSS, you will need a small JavaScript snippet to do that for you.
A simple JavaScript snippet (no jQuery) which you could wrap in a window.load and drop into your project (and be done with) would look like this:
var flexv = document.querySelectorAll('div.flexv');
/* iterate the instances on your page */
[].forEach.call(flexv, function(div) {
var children = [].slice.call(div.children), // get all children
flexChild = children.splice(-1, 1), // get the last child
usedHeight = 0, totalHeight = div.offsetHeight;
children.forEach(function(elem) {
usedHeight += elem.offsetHeight; // aggregate the height
});
/* assign the calculated height on the last child */
flexChild[0].style.height = (totalHeight - usedHeight) + 'px';
});
The CSS snippet is more or less like the horizontal one, sans table layout, which also you could just drop into your project and just add the additional site-specific styling. Minimal markup required remains the same.
Demo Fiddle 2: http://jsfiddle.net/abhitalks/Ltcuxdwf/
Demo Snippet:
document.addEventListener("load", flexit);
function flexit(e) {
var flexv = document.querySelectorAll('div.flexv');
[].forEach.call(flexv, function(div) {
var children = [].slice.call(div.children),
flexChild = children.splice(-1, 1),
usedHeight = 0, totalHeight = div.offsetHeight;
children.forEach(function(elem) {
usedHeight += elem.offsetHeight;
});
flexChild[0].style.height = (totalHeight - usedHeight) + 'px';
});
}
div.flexv {
display: inline-table; box-sizing: border-box; padding: 0; margin: 0;
overflow: hidden;
/* Override your custom styling below */
height: 320px; width: 20%; border: 1px solid black; font-size: 1em;
margin: 8px;
}
div.flexv > div {
display: block; height: auto; box-sizing: border-box;
overflow: hidden;
/* Override your custom styling below */
background-color: lightgreen; border: 1px solid #ddd;
padding: 5px 15px;
}
div.flexv > div:first-child {
/* Override your custom styling below */
min-height: 36px; height: 36px; max-height: 36px;
background-color: orange;
}
div.flexv > div:last-child {
height: 100%;
/* Override your custom styling below */
background: skyblue;
}
<div class="flexv">
<div>36px Fixed Height</div>
<div>Variable Content Height</div>
<div>Flexible Remaining Height</div>
</div>
<div class="flexv">
<div>36px Fixed Height</div>
<div><img src='//placehold.it/64x72/66c' /></div>
<div>Flexible Remaining Height</div>
</div>
<div class="flexv">
<div>36px Fixed Height</div>
<div>Variable Text Height</div>
<div>
<img src='//placehold.it/72x48/66c' />
<p>Variable Content Height</p>
</div>
<div>Flexible Remaining Height</div>
</div>
Note: As pointed out by #LGSon, the display: inline-table used for the demo does not play well with Firefox. This is only for a demo and should be replaced by either block or inline-block as per your use-case.
Updated
As I commented earlier, and besides flex, this is also solvable using display: table and here is a fiddle demo I made showing that.
If a fixed top also were required for the vertical demo, here is an update of my original display:table version: fiddle demo
Sometimes I haven't been able (or didn't want) to use either flex nor tables, and I have, on and off, looked into making use of css calc() and css attr().
Both come short though, as calc() can only use +-*/ and attr() can only return a string value, which can't be computed by calc().
My suggestion, using plain javascript, is based on that these 2 methods, at some point, might be extended so we can make better use of them.
This is how I would like see them work;
width: calc(100% - attr(this.style.left))
but as they don't, and I can't add it to my css either as it wouldn't validate properly (might even break the parsing, who knows) I added a variant as an attribute on the element instead, with some quirks to make it easier to compute.
And in this case (the 2 demos) it looks like this:
//height
<div id="bottom" data-calcattr="top,height,calc(100% - toppx)">...</div>
//width
<div class="box right" data-calcattr="left,width,calc(100% - leftpx)">...</div>
Together with below script, which by no means is fully developed/tested on all property combinations, it does adjust the div's size.
In short, when runned, it take the attribute, split it into an array, take the first item value as from which property to read, the second to which property to set and the third to which the read value gets inserted/replaced and assigned to the property to be set (hmmm, still working on a better way to express this, but hopefully the script is clear enough with whats going on).
Here is a fiddle showing both the height and width demo, integrated, making use of the same script.
function calcattr() {
var els = document.querySelectorAll('[data-calcattr]');
for (i = 0; i < els.length; i++) {
var what = els[i].getAttribute('data-calcattr');
if (what) {
what = what.split(',');
var rect = els[i].getBoundingClientRect();
var parentrect = els[i].parentNode.getBoundingClientRect();
var brd = window.getComputedStyle(els[i].parentNode,null).getPropertyValue('border-' + what[0] + '-width');
what[2] = what[2].replace(what[0],parseInt(rect[what[0]]-parentrect[what[0]]) - parseInt(brd));
els[i].setAttribute("style", what[1] + ":" + what[2]);
}
}
}
IN CSS
Although I've never tried it, I believe that this would work:
.top {
height:13px;
}
.main {
height:calc(100% - var(height));
}
http://www.creativebloq.com/netmag/why-you-need-use-css-variables-91412904
IN SASS
$top_height: 50px
.main {
height: calc(100% - $top_height)
}
Sass Variable in CSS calc() function
In both cases on container css you should put:
#container {
overflow: hidden;
}
But, it will hide the information that overflows the container. I think that is the point, since you put white-space: nowrap; it means that you don't want to change the height, so you have to hide the text that can't fits the container.
I have a div with height = 10*screen-height.
I want to add another smaller div to it with height = screen height
Assuming that I can add 10 such smaller div's onto the bigger div, I want to add this div at particular position on the bigger div. Say starting from 4*screenheight pixel. How do I do that using jQuery?
Presumably you already have the screen height stored, and the two divs created at the correct heights, so:
$(inner_div).css('position', 'relative').css('top', 4*screen_height);
You may not need position:relative in your style if it's in your css already
See here how you can access and manipulate the body's height and the big div's inners afterwards;
JSfiddle
HTML
<div id="biggy">
<div class="smally">Smally :)</div>
<div class="smally">Smally 2, don't forget me :D</div>
</div>
CSS
html, body {
height: 100%;
padding: 0px;
margin: 0px;
}
#biggy {
width: 200px;
background-color: orange;
position: relative;
}
.smally {
width: 100%;
background-color: blue;
color: white;
text-align: center;
position: absolute;
}
JavaScript
$(document).ready(function() {
var bh = $('body').height();
var smally_offset = (bh / 10);
// Set biggy to be the body's height
$('#biggy').css('height', bh);
// Make all smallies 10% of the set height
$('.smally').css('height', smally_offset);
// Handle the different smallies :)
$('.smally:nth-child(1)').css('top', smally_offset * 0);
$('.smally:nth-child(2)').css('top', smally_offset * 1);
});