Looking for a way to make sure that the height of an article element is never greater than 65% of the viewport height. Also there's an image nested inside the element that must be contained to the height of it's parent and be able to scaledown to the max-height and keep the it's ratio (yes, the image should be fully visible, no cropping).
It's also important that img and the overlaying div .actions have the same width at all times.
Is this possible with css only?
This is just a test case, there's other elements like this, the markup is the same, but the ratio of the element within each element is unique.
Demo
http://jsfiddle.net/SpPDp/show/
Code
http://jsfiddle.net/SpPDp/
Source below
<article>
<div class="inner">
<div class="overlay">
<div class="actions">
<div class="text">Text</div>
<div class="yep">Yep</div>
<div class="heretoo">Here too</div>
</div>
</div>
<div class="content">
<img src="http://lorempixel.com/output/abstract-h-g-600-900-4.jpg">
</div>
</div>
</article>
article {
float: left;
width: 40%;
}
article .inner {
position: relative;
}
article .overlay {
position: absolute;
background: #000;
opacity: 0.7;
top: 0; right: 0; bottom: 0; left: 0;
height: 100%;
overflow: hidden;
}
article .actions {
text-align: center;
position: absolute;
bottom: 1%;
width: 100%;
color: #fff;
background: red;
}
.text {
float: left;
}
.yep {
display: inline-block;
}
.heretoo {
float: right;
}
article img {
max-width: 100%;
}
First, let me say that the ability to change even the tiniest part of your html would make it so much easy to accomplish the result.
For example, setting the image as background, and accepting the fact that it should be cropped, would make the task a no-brainer.
But you make it clear that:
Articles must be max 65% of viewport h;
The meta bar over it should always have the same width as the image;
Images must not be cropped nor distorted.
If your question is formulated correctly, which I really hope it is, since we are all trying to solve it, you imply that articles widths won't always be equal.
The solution is to let the image figure out what is best to do. First, we set it's max-size in vw and vh, then we clear the way of unwanted positionings and sizes, to allow the size of the image to go up to the container, then back down to the meta bar in the overlay. Also, notice the use of flex boxes.
Here's the CSS (I didn't touch the HTML)
article {
float: left;
overflow: hidden;
vertical-align: top;
}
.inner {
/* older browsers. you should add the other prefixes too. there are polyfills to have broader support, check link later in the answer */
display: -webkit-box;
display: -moz-box;
display: -ms-box;
display: box;
-webkit-box-orient: vertical;
-moz-box-orient: vertical;
-ms-box-orient: vertical;
box-orient: vertical;
-webkit-box-direction: reverse;
-moz-box-direction: reverse;
-ms-box-direction: reverse;
box-direction: reverse;
/* newer */
display: -webkit-flex;
display: -moz-flex;
display: -ms-flex;
display: flex;
-moz-flex-direction: column-reverse;
-ms-flex-direction: column-reverse;
-webkit-flex-direction: column-reverse;
flex-direction: column-reverse; /* the meta box is added
after the image container, and the items are arranged in column */
}
.overlay {
z-index: 2;
margin: 0 0 -25px; /* magic: this cuts the container by 25px (height of meta bar) */
}
.actions {
color: #fff;
background: rgba(200,0,0,0.8);
/* older */
display: -webkit-box;
display: -moz-box;
display: -ms-box;
display: box;
-webkit-box-pack: justify; /* distribute the labels */
-moz-box-pack: justify;
-ms-box-pack: justify;
box-pack: justify;
-webkit-box-direction: normal; /* reset order (it used to be inherited) */
-moz-box-direction: normal;
-ms-box-direction: normal;
box-direction: normal;
/* newer */
display: -webkit-flex;
display: -moz-flex;
display: -ms-flex;
display: flex;
-webkit-justify-content: space-between; /* distribute the labels */
-moz-justify-content: space-between;
-ms-justify-content: space-between;
justify-content: space-between;
/* move up */
-webkit-transform: translate(0,-25px);
-moz-transform: translate(0,-25px);
-ms-transform: translate(0,-25px);
transform: translate(0,-25px);
box-shadow: 0 -1000px 0 1030px rgba(0,0,0,.6); /* since it
can't actually know the size, the overlay is accomplished with
a shadow. as long as it is not blurred, it won't impact
performances much */
font-size: 1.4vw; /* the only hard limit now is the width
of the text */
}
.content {
z-index: -1;
position: relative;
/* commenting those 2 last properties has two effects in webkit. 1) it avoids the images to stretch. 2) when you resize your window, the images won't adapt. only on load/refresh. this should be ok though, as window resizing is not really what responsive is most useful for
--- old code ---
display: -webkit-box;
display: -ms-box;
display: -moz-box;
display: box;
--- new code ---
display: -webkit-flex;
display: -moz-flex;
display: -ms-flex;
display: flex; */
}
.content img {
max-width: 40vw; /* and here you finally set the sizes.
note that you can set a min-width too, if you want, but
if you do there will be some image ratio that will force
them to stretch */
max-height: 65vh;
}
The code: http://jsfiddle.net/frapporti/NssKa/
The result, with many images of different ratios: http://jsfiddle.net/frapporti/NssKa/embedded/result/
Off course, this is just theory and is a valid answer to your question.
If you want to use this in production you should add some good polyfill for the older browsers, perhaps you could add this polyfill. As you can see I have already added the older box model properties as fallback.
Should be, there's no reason why not. Percentage heights are very useful.
You need to add this to the image tag:
<img src="whatever.jpg" width="95%">
It can be any value, depending on how wide you want it. As long as you make sure not to specify a height, it will keep scale.
Your CSS should change to be more like this:
article {
height:65%;
max-height:65%;
/* plus whatever else you want*/
}
As long as the parent is 100% window height, the article will be 65% window beight. Clearly if it's more, the article will be more.
The other solution is JavaScript. However, since you ask for CSS I'll omit that.
CSS:
article{
height:65%;
max-height:65%;
overflow:scroll; /* or hidden */
}
article .content > img{
max-height:100%;
width:auto;
}
JS Control (Because relative elements may not have a percentage height)
$(function(){
var $article = $('article');
var $height = $(window).height() * 0.65;
$article.css({'height':$height+'px', 'max-height':$height+'px'});
});
You should first set the 'inner' to 65% and then 'content' and image to 100% height. Like this,
.inner{
height:65%;
}
.content{
height:100%;
}
.content img{
height:100%;
}
I wrote a solution using vanilla Javascript. Why have jQuery as a dependency unless you need to? (rhetorical).
var viewport = document.documentElement.clientHeight;
var el = document.getElementsByTagName("article");
Array.prototype.forEach.call(el, function(el) {
el.style.maxHeight = Math.floor((viewport/100)*65)+"px";
});
http://jsfiddle.net/PgtAY/
I am trying to layout a header that will resize vertically to fit the content, and a footer that will resize vertically the remaining then scroll any overflow given a fixed size container. Using CSS box-flex I have an example that works in Chrome but not Firefox (http://jsfiddle.net/V4Uc2/). What CSS styles do I need to add to ensure that Firefox doesn't allow any overflow from the container and acts like Chrome? Here is inlined code:
<style>
.container
{
background: #fee;
height: 400px;
width: 400px;
display: -webkit-box;
display: -moz-box;
display: box;
-webkit-box-orient: vertical;
-moz-box-orient: vertical;
box-orient: vertical;
}
.header
{
background: #fee;
-webkit-box-flex: 0;
-moz-box-flex: 0;
box-flex: 0;
}
.footer
{
background: #eef;
overflow: auto;
-webkit-box-flex: 1;
-moz-box-flex: 1;
box-flex: 1;
}
</style>
<div class="container">
<div class="header">...</div>
<div class="footer">...</div>
</div>
Add
width: 100%;
in your footer css description.
That prevents an overflow horizontally, firefox keeps your 400px then as a fixed width.
I have a flexbox div that allows a SINGLE child element. So far I've been able to get alignments of the child working nicely (top, left, right, bottom, etc), including vertical stretch. I also want to be able to support horizontal stretch at the same time as vertical ('at the same time' seems to be the key).
I've been able to accomplish horizontal stretch by setting the 'flex' property to '1 100%' on the child element, however this appears to ignore any padding applied to the parent element(and any margin applied to the child node for that matter).
Looking at the flexbox spec, I'm not able to find any other way to do this along the main axis of the flexbox. Cross-axis stretch is no problem.
It is possible. And here is a small sample which shows you how:
.centerbox {
/* basic styling */
width: 350px;
height: 95px;
font-size: 14px;
border: 1px solid #555;
background: #CFC;
/* flexbox, por favor */
display: -webkit-box;
-webkit-box-orient: horizontal;
-webkit-box-pack: center;
-webkit-box-align: center;
display: -moz-box;
-moz-box-orient: horizontal;
-moz-box-pack: center;
-moz-box-align: center;
display: box;
box-orient: horizontal;
box-pack: center;
box-align: center;
}
<!DOCTYPE html>
<html>
<head>
<style>
.centerbox {
/* basic styling */
width: 350px;
height: 95px;
font-size: 14px;
border: 1px solid #555;
background: #CFC;
/* flexbox, por favor */
display: -webkit-box;
-webkit-box-orient: horizontal;
-webkit-box-pack: center;
-webkit-box-align: center;
display: -moz-box;
-moz-box-orient: horizontal;
-moz-box-pack: center;
-moz-box-align: center;
display: box;
box-orient: horizontal;
box-pack: center;
box-align: center;
}
</style>
</head>
<body>
<div class="centerbox">
<textarea>resize me, please</textarea>
</div>
</body>
</html>
FYI: Axel Russell did some great work on writing a class for multi browser support: http://infrequently.org/2009/08/css-3-progress/
Although you found your solution, I think the next snippet could be handy to all developers (such as myself) who searched for a general solution.
http://jsfiddle.net/EL2KL/1/
I'd be happy if you publish fiddle with your solution.
p.s. thanks to Jiri (the flex master)
after researching the flexible box model for a whole day, I must say I really like it. It implements the functionality I implement in JavaScript in a fast and clean way. One thing however bugs me:
I can't expand a div to take the full size calculated by the flexible box model!!!
To illustrate it I'll proved an example. In it the two flexible places take the exact with and height, but the div inside it only takes the height of the "<p>...</p>" element. For this example it doesn't matter but what I originally was trying was placing a "flexible box model" inside another "flexible box model" and this must be possible in my opinion
html, body {
font-family: Helvetica, Arial, sans-serif;
width: 100%;
height: 100%;
margin: 0px;
padding: 0px;
}
#box-1 {
background-color: #E8B15B;
}
#box-2 {
background-color: #C1D652;
}
#main {
width: 100%;
height: 100%;
overflow-x: auto;
overflow-y: hidden;
}
.flexbox {
display:-moz-box;
display:-webkit-box;
display: box;
text-align: left;
overflow: auto;
}
H1 {
width: auto;
}
#box-1 {
height: auto;
-moz-box-orient: vertical;
-webkit-box-orient: vertical;
box-orient: vertical;
-moz-box-flex: 3;
-webkit-box-flex: 3;
box-flex: 3;
}
#box-2 {
height: auto;
min-width: 50px;
-moz-box-orient: vertical;
-webkit-box-orient: vertical;
box-orient: vertical;
-moz-box-flex: 1;
-webkit-box-flex: 1;
box-flex: 1;
}
#fullsize{
background-color: red;
height: 100%;
}
<div id="main" class="flexbox">
<div id="box-1" class="flexbox">
<div id="fullsize">
<p>Hallo welt</p>
</div>
</div>
<div id="box-2" class="flexbox">
</div>
</div>
I've been wrestling with this myself, but have finally managed to come up with a solution.
See this jsFiddle, although I have only added webkit prefixes so open in Chrome.
You basically have 2 issues which I will deal with separately.
Getting the child of a flex-item to fill height 100%
Set position:relative; on the parent of the child.
Set position:absolute; on the child.
You can then set width/height as required (100% in my sample).
Fixing the resize scrolling "quirk" in Chrome
Put overflow-y:auto; on the scrollable div.
The scrollable div must have an explicit height specified. My sample already has height 100% but if none is already applied you can specify height:0;
See this answer for more information on the scrolling issue.
You must also make the div you want to expand a flex-box as well and add a flex value.
This fixes the problem.
#fullsize{
background-color: red;
display: -webkit-box;
display: box;
display: -moz-box;
box-flex:1;
-webkit-box-flex:1;
-moz-box-flex:1;
}
So, this web application I'm working in haves three vertical columns expanding for the entire window height, and a footer div expanding for the entire width. The layout looks like this:
+|+
---
where + means a liquid column, | means a fixed column, and - the footer.
I've done the element positioning using absolute and relative positioning with some tweaks using jQuery. But I want to know if there is a way of doing this with CSS3 only.
Thanks!
This neglects all browser not supporting the box-orient and box-flex properties (like IE).
Demo: http://jsfiddle.net/p8vBC/11/
CSS:
html, body {
height: 100%;
padding: 0px;
margin: 0px;
}
body > #main {
display: -webkit-box;
-webkit-box-orient: horizontal;
display: -moz-box;
-moz-box-orient: horizontal;
display: box;
box-orient: horizontal;
height: 100%;
margin-bottom: -100px;
}
footer {
height: 100px;
box-flex: 1;
-webkit-box-flex: 1;
-moz-box-flex: 1;
}
aside {
box-flex: 1;
-webkit-box-flex: 1;
-moz-box-flex: 1;
}
#content {
width: 400px;
}
HTML:
<div id="main">
<aside id="left"></aside>
<div id="content"></div>
<aside id="right"></aside>
</div>
<footer></footer>