I have .container > .wrapper > img. Here is a task:
img must have maximum width/height possible, keeping it's aspect ratio, being 100% visible and not exceeding the .container's size.
Image must not exceed it's natural size.
Width/height of the image are not known.
.container is known to be of a fixed (in pixels) width/height, but exact dimensions are not known.
.wrapper must tightly fit the img (must have same width and height as the image). Wrapper is a special element to put content over the image, e. g. badges. I added example labels to the snippet to demonstrate this. This should somehow be possible.
Markup:
<div class="container">
<div class="wrapper">
<div class="label">new!</div>
<img src="https://via.placeholder.com/150x300">
</div>
</div>
I thought I can use display: block; max-height: 100% for the img, but it does not work, because .wrapper (image parent) height is not fixed, and it can't be fixed - see point 5.
What else can I do to achieve described task with pure CSS? I'd prefer solution that works in IE11, but others will be also appreciated.
EDIT: It is really important that container and image can be of any size. I added settings to the snippet for tests on different sizes.
If an image is larger than container, it should render not larger than container.
If an image is smaller than container, it should render not larger than is's natural size.
It should work with horizontal container/vertical image AND vertical container/horizontal image.
EDIT 2: It is also really important that .wrapper is not just a "nasty interfering" element. It is functional: wrapper is used to place absolute positioned content over the image inside it (e.g. labels, badges), it must support transforms (mirror, translate), css filters etc, generally speaking - all the stuff we usually do with block elements.
Playground:
$(function() {
$('input[name=container-width]').on('change', function() {
$('.container').css('width', $(this).val() + 'px')
})
$('input[name=container-height]').on('change', function() {
$('.container').css('height', $(this).val() + 'px')
})
$('input[name=image-width]').on('change', function() {
var width = $(this).val()
var height = $('input[name=image-height]').val()
$('img')[0].src = 'http://via.placeholder.com/' + width + 'x' + height
})
$('input[name=image-height]').on('change', function() {
var height = $(this).val()
var width = $('input[name=image-width]').val()
$('img')[0].src = 'http://via.placeholder.com/' + width + 'x' + height
})
})
.container {
width: 200px; /* can have any value in pixels */
height: 200px; /* can have any value in pixels */
background-color: green;
}
.wrapper {
outline: 1px solid yellow;
position: relative; /* for label */
}
.label {
position: absolute;
background-color: blue;
color: white;
}
.label.-top-left {
top: 10px;
left: 10px;
}
.label.-bottom-right {
bottom: 10px;
right: 10px;
}
<h2>Settings</h2>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Container: width <input type="number" step="10" name="container-width" value="200"> height <input type="number" step="10" name="container-height" value="200">
<br>
Image: width <input type="number" step="10" name="image-width" value="150"> height <input type="number" step="10" name="image-height" value="300">
<br>
<br>
<h2>Demo</h2>
<div class="container">
<div class="wrapper">
<div class="label -top-left">new!</div>
<div class="label -bottom-right">good!</div>
<img src="http://via.placeholder.com/150x300">
</div>
</div>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<h2>How it should look like</h2>
<p>This is not the solution, because is has many hardcoded dimensions. It's just a visual demo of what I want to achieve.</p>
<div style="width: 200px; height: 200px;background-color: green">
<div style="width: 100px; height: 200px; position: relative;outline: 1px solid yellow">
<div style="position: absolute;
top: 10px;
left: 10px;
background-color: blue;
color: white;">new!</div>
<div style="position: absolute;
bottom: 10px;
right: 10px;
background-color: blue;
color: white;">good!</div>
<img style="max-width: 100%; max-height: 100%;" src="http://via.placeholder.com/150x300">
</div>
</div>
Does this work for you?
.container {
width: 200px;
/* can have any value in pixels */
height: 200px;
/* can have any value in pixels */
background-color: green;
}
.container-2 {
width: 300px;
height: 300px;
}
.wrapper {
outline: 1px solid yellow;
display: inline;
height: inherit;
}
img {
width: auto;
max-height: 100%;
display: inline-block;
vertical-align: bottom;
}
<div class="container">
<div class="wrapper">
<img src="http://via.placeholder.com/150x300">
</div>
</div>
<br>
<div class="container container-2">
<div class="wrapper">
<img src="http://via.placeholder.com/30">
</div>
</div>
check out below code this should work for you
you need to apply max-width: 100% and max-height:100% to your img
and display: inline; to your img parent div
.container {
width: 200px; /* can have any value in pixels */
height: 200px; /* can have any value in pixels */
background-color: green;
}
.wrapper {
outline: 1px solid yellow;
display: inline;
}
.wrapper img{
max-width: 100%;
max-height: 100%;
height: auto;
vertical-align: top;
}
<div class="container">
<div class="wrapper">
<img src="http://placehold.it/150x300">
</div>
</div>
<hr/>
<div class="container">
<div class="wrapper">
<img src="http://placehold.it/1500x800">
</div>
</div>
Update
Added vertical-align: top; to image to fixed extra gap at bottom as pointed out by #TemaniAfif
Add image using background-image on wrapper element
.wrapper {
outline: 1px solid yellow;
background: url(http://via.placeholder.com/150x300);
background-size: cover;
width: 100%;
height: 100%;
background-repeat: no-repeat;
}
$(function() {
$('input[name=container-width]').on('change', function() {
$('.container').css('width', $(this).val() + 'px')
})
$('input[name=container-height]').on('change', function() {
$('.container').css('height', $(this).val() + 'px')
})
$('input[name=image-width]').on('change', function() {
var width = $(this).val()
var height = $('input[name=image-height]').val()
$('img')[0].src = 'http://via.placeholder.com/' + width + 'x' + height
})
$('input[name=image-height]').on('change', function() {
var height = $(this).val()
var width = $('input[name=image-width]').val()
$('img')[0].src = 'http://via.placeholder.com/' + width + 'x' + height
})
})
.container {
width: auto; /* can have any value in pixels */
height: auto; /* can have any value in pixels */
background-color: green;
}
.wrapper {
width: 100%;
height: 100%;
outline: 1px solid yellow;
}
.container > .wrapper > img {
width: 100%;
height: 100%;
opacity: .8;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h2>Settings</h2>
Container: width <input type="number" step="10" name="container-width" value="200"> height <input type="number" step="10" name="container-height" value="200">
<br>
Image: width <input type="number" step="10" name="image-width" value="150"> height <input type="number" step="10" name="image-height" value="300">
<br>
<br>
<h2>Demo</h2>
<div class="container">
<div class="wrapper">
<img src="http://via.placeholder.com/150x300">
</div>
</div>
What about this ?
.container{
width: 200px;
height: 200px;
background-color: green;
}
.wrapper {
outline: 1px solid yellow;
height:100%;
}
img{
height: 100%;
}
Related
I have a side menu which i would like to keep at 100% page height.
The code is basically just like this right now:
body,
html {
width: 100%;
height: 100%;
}
.sideMenu {
width: 200px;
height: 100%;
float: left;
}
The problem with this is that the side menus height does not extend with the rest of the page. For example I have input fields that can be added to a form, and when a few inputs have been added the form extends below the original view port. While the menu does not.
Heres a jsfiddle to demonstrate https://jsfiddle.net/m5yfqdsu/, click the "add row" button to add inputs until theyre below the viewport.
So what is the best solution to keep the menu at 100% height?
Prefer a CSS solution, but JS works as well if needed.
Add position: fixed; to .sideMenu
// just a quick function to add more inputs
$(document).ready(function() {
$(".add").on("click", function() {
$("fieldset").append("<div class='rowContainer'><label>Label:</label><input type='text' /></div>");
});
});
* {
margin: 0;
padding: 0
}
body,
html {
width: 100%;
height: 100%;
}
fieldset {
padding: 10px;
}
.sideMenu {
width: 200px;
height: 100%;
background-color: #1c1c1c;
position: fixed;
top: 0;
left: 0;
}
.wrapper {
margin-left: 200px;
}
input {
width: 100%;
max-width: 400px;
height: 40px;
display: block;
margin-bottom: 20px;
color: #000;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="sideMenu"></div>
<div class="wrapper">
<h1>Page Title</h1>
<form>
<fieldset>
<div class="rowContainer">
<label>Label:</label>
<input type="text" />
</div>
<div class="rowContainer">
<label>Label:</label>
<input type="text" />
</div>
<div class="rowContainer">
<label>Label:</label>
<input type="text" />
</div>
</fieldset>
</form>
<button class="add">Add row</button>
</div>
You can solve this in multiple ways.
One way is to make a container having 100% height, making its child elements scrollable. That way you don't need the actual absolute rule, but it does achieve the same result. I prefer not using absolute because that makes it easier if you want it to be responsive eventually.
That way, you can scroll the sidebar and content seperatly. Both won't be bigger then they need to be. If the sidebar grows, it will be scrollable too.
* {
margin:0;
padding:0;
}
html, body, .wrapper {
height:100%;
}
.wrapper {
position:relative;
overflow-y:hidden;
}
.sidebar {
width:100px;
float:left;
height:100%;
overflow-y:auto;
background-color:red;
}
.content {
width:300px;
float:left;
height:100%;
overflow-y:auto;
background-color:blue;
}
.spacer {
height:1000px;
}
<div class="wrapper">
<div class="sidebar">
sidebar
</div>
<div class="content">
content
<div class="spacer">
spacer
</div>
</div>
</div>
Is there a way to achieve the following behavior in css/html :
Please note the green side bar has not to be responsive but I cannot give it a fixed width with
width: XX px;
because it can contain more or less elements, so no idea of XX in advance.
The brown bar has to be responsive and takes all the remaining width.
Thanks in advance for any trick! I have tried tables but with no success as we can't specify a div to restrict its with to what is necessary.
You can achieve that easily with flexbox. Here's the example:
http://codepen.io/anon/pen/JKXXNE
#container {
display:flex;
}
#sidebar, #content {
height: 100px;
}
#sidebar {
background-color: green;
}
#content {
background-color: brown;
flex: 1;
}
You can use Flexbox, and if you set flex: 1 on right div it will take rest of free space and width of left div will still be dynamic.
.parent {
display: flex;
border: 2px solid black;
}
.left {
background: #22B14C;
padding: 10px;
}
.right {
background: #EFE4B0;
padding: 10px;
flex: 1;
}
span {
margin: 0 20px;
}
<div class="parent">
<div class="left"><span>Span</span><span>Span</span></div>
<div class="right">Right</div>
</div>
This can also be done with CSS Table layout you just need to set width: 100% on .right div and it will take rest of free space
.parent {
display: table;
border: 2px solid black;
}
.left {
background: #22B14C;
display: table-cell;
padding: 10px;
}
.right {
background: #EFE4B0;
display: table-cell;
width: 100%;
padding: 10px;
}
span {
margin: 0 20px;
}
<div class="parent">
<div class="left"><span>Span</span><span>Span</span></div>
<div class="right">Right</div>
</div>
For older browsers, use display: table
html, body{
height: 100%;
margin: 0;
}
.tbl{
display:table;
}
.row{
display:table-row;
}
.cell{
display:table-cell;
}
.content{
width: 100%;
}
#left_col {
background: orange none repeat scroll 0 0;
width: 1%;
}
#right_col {
background: green none repeat scroll 0 0;
width: 100%;
}
<div class="tbl content">
<div class="row">
<div id="left_col" class="cell">
wide content <br>
content <br>
wider contentcontent <br>
</div>
<div id="right_col" class="cell"></div>
</div>
</div>
Another way to achieve this without using flexbox can be:
Working Fiddle:
https://jsfiddle.net/y00e5w6m/
(Note i have used sample css and input just to showcase how this can be done. This should be tuned a bit according to requirements)
Sample Output:
Html:
<div style="float:left;width:100%;border:1px solid #000;">
<div id="dynamic-content" style="float:left;background-color:#090;border:1px solid #900">
<div style="float;left;">
Mango
</div>
<div style="float;left;margin-left:5px;">
Banana
</div>
<div style="float;left;margin-left:5px">
Orange
</div>
</div>
<div id="other-content" style="float:left;background-color:#630;border:1px solid #009;">
</div>
</div>
JS:
var items=["mango","grapes","banana"];
var windowWidth = $(window).width();
console.log(windowWidth);
var dynamicContentWidth = $("#dynamic-content").width();
console.log(dynamicContentWidth);
var otherContentWidth = dynamicContentWidth >= windowWidth ? windowWidth : windowWidth-dynamicContentWidth-20;
console.log(otherContentWidth);
$("#other-content").width(otherContentWidth);
$("#other-content").height($("#dynamic-content").height());
In my body i want two divs with content side by side that each has a width of 50% of the screen. But i want to be able to hide/show the first div and then the second divs width responds to this changing it's width to 100% or 50%. Filling the body or the rest of the body depending on if the first div is hidden.
Any ideas how to do this? (I know how to show/hide with jquery, im thinking of the HTML)
Use floating only to the first element, and let the second one fit the remaining space.
Then, if the element is visible with width:50%, the second one will fill the other half. But if the first one is hidden, the second one will fill whole screen.
Demo
HTML:
<input type="button" id="btn" value="toggle" />
<div id="wrapper">
<div id="left">Foo</div>
<div id="right">Bar</div>
</div>
CSS:
#wrapper, #right {
overflow: hidden;
}
#left {
float: left;
width: 50%;
background-color: #ffa;
}
#right {
background-color: #faf;
}
.hide {
display: none;
}
JS:
var left = document.getElementById('left');
document.getElementById('btn').onclick = function() {
left.className = left.className ? '' : 'hide';
};
Another possibility: use display: table-cell. This has the advantage over floats that both columns will have same height, and setting wrapper's height will also set it for both columns.
Demo
HTML:
<input type="button" id="btn" value="toggle" />
<div id="wrapper">
<div id="left">Foo</div>
<div id="right">Bar</div>
</div>
CSS:
#wrapper {
display: table;
width: 100%;
}
#left, #right {
display: table-cell;
}
#left {
background-color: #ffa;
}
#right {
background-color: #faf;
}
.hide {
display: none !important;
}
JS:
var left = document.getElementById('left');
document.getElementById('btn').onclick = function() {
left.className = left.className ? '' : 'hide';
};
You can use flexbox and JQuery to do this with as many divs as you'd like.
https://jsfiddle.net/L8kfty5n/5/
function hideandshow() {
if ($('.hide').is(":checked"))
$("#div1").show();
else
$("#div1").hide();
}
.container {
display: flex;
flex-flow: row nowrap;
}
#div1,
#div2,
#div3 {
flex-grow: 1;
flex-basis: calc(100% / 3);
border: 1px solid #000;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.0/jquery.min.js"></script>
<div class="container">
<div id="div1">This disappears</div>
<div id="div2">This grows</div>
<div id="div3">This grows too</div>
</div>
<input class="hide" type="checkbox" name="hide" value="1" onchange="hideandshow()" checked/>
I have a page that looks like this jsfiddle, code below:
html:
<div class="parent">
<div class="child">
<input type="text">
<input type="submit">
</div>
</div>
css:
.parent { width: 500px; }
.child { width: 100%; }
How do I get it so that together they take up 100% of the parent div width (with the text input stretching accordingly)?
To clarify: I want the button(s) in a row to be fixed width and the input to take up the remaining width of the parent so that together the width = parent width. In the case that there are no button in the row, I'd like the textinput to take up the whole width.
.parent { width: 500px; margin:auto; }
.child { width: 100%; }
add this to make input stretches to full width
.child input { width: 100%; }
There are many ways to do this. One way to do this is to use the display:table-x attribute.
If you wrap the input elements in a div of their own like so:
<div class="parent">
<div class="text">
<input type="text" />
</div>
<div class="button">
<input type="submit" />
</div>
</div>
Then style the parent as display:table, the wrapper div's as display:table-cell, and give a width to div.button, like so:
.parent {
width: 500px;
background-color:blue;
display:table;
}
.text {
display:table-cell;
}
.text input {
width:100%;
-webkit-appearance:none;
}
.button {
display:table-cell;
background-color:red;
width:100px;
}
Then you can achieve the result you are looking for: http://jsfiddle.net/QpCCD/9/
This is similar to #panindra's post, but it keeps both inputs on the same line.
I've added some color to the sample to be able to see the position on the screen.
<html>
<head>
<style type="text/css">
body { background-color: black; }
.parent { width: 500px; background-color: white; text-align: center; }
.child { width: 100%; position: relative; margin: 0px 0px 0px 0px; border: 0px; }
.child input { width: 49%; margin: 0px 0px 0px 0px; border: 0px; }
</style>
</head>
<body>
<div class="parent">
<div class="child">
<input type="text">
<input type="submit">
</div>
</div>
</body>
</html>
Actually, this would be closer:
.child input { width: 248px; }
I have this problem, I have two divs:
<div style="width:100%; height:50px;" id="div1"></div>
<div style="width:100%;" id="div2"></div>
How do I make div2 occupy remaining height of the page?
Use absolute positioning:
#div1{
width: 100%;
height: 50px;
background-color:red;/*Development Only*/
}
#div2{
width: 100%;
position: absolute;
top: 50px;
bottom: 0;
background-color:blue;/*Development Only*/
}
<div id="div1"></div>
<div id="div2"></div>
You can use this http://jsfiddle.net/Victornpb/S8g4E/783/
#container {
display: table;
width: 400px;
height: 400px;
}
#container > div{
display: table-row;
height: 0;
}
#container > div.fill{
height: auto;
}
Just apply the class .fill to any of the children to make then occupy the remaining height.
<div id="container">
<div>
Lorem ipsum
</div>
<div>
Lorem ipsum
</div>
<div class="fill"> <!-- this will fill the remaining height-->
Lorem ipsum
</div>
</div>
It works with how many children you want, no additional markup is required.
Demo
One way is to set the the div to position:absolute and give it a top of 50px and bottom of 0px;
#div2
{
position:absolute;
bottom:0px;
top:50px
}
Since you know how many pixels are occupied by the previous content, you can use the calc() function:
height: calc(100% - 50px);
I faced the same challenge myself and found these 2 answers using flex properties.
CSS
.container {
display: flex;
flex-direction: column;
}
.dynamic-element{
flex: 1;
}
https://stackoverflow.com/a/35348188/1084619
https://stackoverflow.com/a/35348188/1084619
You can use
display: flex;
CSS property, as mentioned before by #Ayan, but I've created a working example: https://jsfiddle.net/d2kjxd51/
With CSS tables, you could wrap a div around the two you have there and use this css/html structure:
<style type="text/css">
.container { display:table; width:100%; height:100%; }
#div1 { display:table-row; height:50px; background-color:red; }
#div2 { display:table-row; background-color:blue; }
</style>
<div class="container">
<div id="div1"></div>
<div id="div2"></div>
</div>
Depends on what browsers support these display types, however. I don't think IE8 and below do. EDIT: Scratch that-- IE8 does support CSS tables.
I tried with CSS, and or you need to use display: table or you need to use new css that is not yet supported on most browsers (2016).
So, I wrote a jquery plugin to do it for us, I am happy to share it:
//Credit Efy Teicher
$(document).ready(function () {
$(".fillHight").fillHeight();
$(".fillWidth").fillWidth();
});
window.onresize = function (event) {
$(".fillHight").fillHeight();
$(".fillWidth").fillWidth();
}
$.fn.fillHeight = function () {
var siblingsHeight = 0;
this.siblings("div").each(function () {
siblingsHeight = siblingsHeight + $(this).height();
});
var height = this.parent().height() - siblingsHeight;
this.height(height);
};
$.fn.fillWidth = function (){
var siblingsWidth = 0;
this.siblings("div").each(function () {
siblingsWidth += $(this).width();
});
var width =this.parent().width() - siblingsWidth;
this.width(width);
}
* {
box-sizing: border-box;
}
html {
}
html, body, .fillParent {
height: 100%;
margin: 0;
padding: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.2/jquery.min.js"></script>
<div class="fillParent" style="background-color:antiquewhite">
<div>
no1
</div>
<div class="fillHight">
no2 fill
</div>
<div class="deb">
no3
</div>
</div>
You could use calc function to calculate remaining height for 2nd div.
*{
box-sizing: border-box;
}
#div1{
height: 50px;
background: skyblue;
}
#div2{
height: calc(100vh - 50px);
background: blue;
}
<div id="div1"></div>
<div id="div2"></div>
<div>
<div id="header">header</div>
<div id="content">content</div>
<div id="footer">footer</div>
</div>
#header {
height: 200px;
}
#content {
height: 100%;
margin-bottom: -200px;
padding-bottom: 200px;
margin-top: -200px;
padding-top: 200px;
}
#footer {
height: 200px;
}
Why not use padding with negative margins? Something like this:
<div class="parent">
<div class="child1">
</div>
<div class="child2">
</div>
</div>
And then
.parent {
padding-top: 1em;
}
.child1 {
margin-top: -1em;
height: 1em;
}
.child2 {
margin-top: 0;
height: 100%;
}