I'm beginning to think this is impossible, but thought I'd ask you guys.
Basically it's a 2 column layout, but the "business" wants the following:
-Always take up the entire browser window
-Accommodate resizing of browser window
-Left column will be fixed width, but that width should be flexible from page-to-page.
-Left column has a region at the top with fixed height.
-Left column has a bottom region. It should take up the remaining vertical space of browser window. If content is very large, it will have a scroll bar just for that region.
-Right column should take up remaining horizontal space of browser window.
-Right column has a region at the top with fixed height.
-Right column has a bottom region. It should take up the remaining vertical space of browser window. If content is very large, it will have a scroll bar just for that region.
I've tried everything...divs, floated, absolutely positioned, tables, divs in tables...
Is this even possible?
Here's an image of what it should look like:
http://imgur.com/zk1jP.png
It's not at all impossible, and you shouldn't need javascript. You do need some IE6 specific hacks if you care about that browser.
The key to the layout is the fact that you can set one or more edge positions on an absolutely positioned element. Here's a good article on the technique: http://www.alistapart.com/articles/conflictingabsolutepositions/
Here's a demo: http://www.spookandpuff.com/examples/2col2section.html
and source:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>2 col, 2 section layout.</title>
<style type="text/css" media="screen">
#leftColumn {
position:absolute;
top:10px;
bottom:10px;
left:10px;
width:400px;
}
#rightColumn {
position:absolute;
top:10px;
bottom:10px;
right:10px;
left:410px;/* This must equal the total width of the #leftColumn, incl padding, border, margin, etc. */
}
.topSection{
position:absolute;
top:10px;
height:120px;
left:10px;
right:10px;
padding:10px;
}
.bottomSection{
position:absolute;
bottom:10px;
top:160px; /* This must equal the total height of the .topSection, incl padding, border, margin, etc. */
left:10px;
right:10px;
padding:10px;
overflow-y:auto;
}
/* Debug styles */
body {background-color:#CCC;}
div {border:1px solid #FFF;}
#leftColumn {background-color:#7EF4B0;}
#rightColumn {background-color:#EEF4A7;}
#leftColumn .topSection{background-color:#56A97A;}
#rightColumn .topSection{background-color:#D6D06D;}
</style>
</head>
<body>
<div id="leftColumn">
<div class="topSection">
<p>Left column, top section.</p>
</div>
<div class="bottomSection">
<p>Left column, bottom section.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
</div>
</div>
<div id="rightColumn">
<div class="topSection">
<p>Right column, top section.</p>
</div>
<div class="bottomSection">
<p>Right column, bottom section.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
</div>
</div>
</body>
</html>
There are a few tricks: First off, I only tested this in Firefox to give you the general idea - there are some needed fixes for IE which I haven't added: check the list apart article up top for details.
I've allowed 10px extra space around all the boxes just to illustrate the idea - you'd probably set these to 0 in a real layout.
You can set the height of .topSection differently between columns with some rules like:
#leftColumn .topSection {height:xxx}
#leftColumn .bottomSection {top:xxx}
#rightColumn .topSection {height:yyy}
#rightColumn .bottomSection {top:yyy}
I would use a container with a class (or a class on the body tag) to specify the width of the left column, something like:
#container.narrow #leftColumn {width:100px}
#container.medium #leftColumn {width:200px}
#container.wide #leftColumn {width:400px}
That allows you to define a set of width 'templates' you can switch between.
It might be worth considering using some javascript to help with your layout problems. Whilst I know this isn't ideal, it is a solution I have used successfully before when trying to deal with full-height layouts.
It should be ok to get the layout you describe without the full height scrolling columns then just use a little bit of javascript to keep them filling the height of the browser
I believe this is fairly easy to do if you have the luxury of using the ext.js framework. Will update with code if no one else offers a better answer and if you're interested.
Update: Here's the code. Tested and works nicely with even IE6. Drawback compared to css-only solution is (i) require JavaScript (mostly likely the app already uses JS); (ii) Ext.js requirement (which might or might not be too feasible):
Notice the usage of style="height: 100px;" int html and autoScroll: true in the JavaScript code. This allows for the fixed height of the top 2 panels and overflow with scrollbars in the bottom twos.
Ext.onReady(function(){
Ext.state.Manager.setProvider(new Ext.state.CookieProvider());
var viewport = new Ext.Viewport({
layout: 'border',
resizable: false,
items: [
{
region: 'west',
id: 'west-panel',
split: false,
width: 300,
margins: '0 0 0 0',
layout: 'border',
items: [{
region: 'north',
contentEl: 'west1',
border: false
},{
region: 'center',
contentEl: 'west2',
border:false,
autoScroll: true
}]
},
{
region:'center',
id:'center-panel',
split:false,
margins:'0 0 0 0',
layout:'border',
items: [{
region: 'north',
contentEl: 'center1',
border:false
},{
region: 'center',
contentEl: 'center2',
border:false,
autoScroll: true
}]
}
]
});
});
and the html:
<div id="west1" style="height: 70px;background-color: #AAA;">
<p>Hi. I'm fixed.</p>
</div>
<div id="west2">
<p> long content goes here</p>
</div>
<div id="center1" style="height: 100px;background-color: #333;color: #FFF;">
<p>Hi. I'm fixed too.</p>
</div>
<div id="center2">
<p> long content goes here</p>
</div>
Demo will be available later, again, if you or anyone is interested. Please indicate so if you could.
You'll get there with faux columns.
You can use that technique to make the two vertical separations.
If you want separate scrollbars (please don't, you'll make usability kitten cry) you can make each of the vertical separations have max-height: 100%; overflow: auto; to make them get scroll if they reach 100% height.
For the "floating-top" blue bars, you can give the parent separation position: relative; padding-top: 150px;, and then give the blue bar position: absolute; top: 0px; left: 0px; width: 100%; height: 150px; overflow: hidden;. (I'm not sure about the 100% width.)
Then the green and yellow content will not overlap it.
Related
It is not entirely clear to me how CSS transforms affect the flow layout of the document and the positioning of an element. According to the documentation on MDN and W3C, CSS transforms do not interfere with the flow layout:
From MDN on CSS transforms (emphasis mine):
By modifying the coordinate space, CSS transforms change the shape and position of the affected content without disrupting the normal document flow.
Thus, if we translate an element, the original flow layout should remain intact and the result of the transformation should be purely visual.
A trivial example of this is demonstrated below:
.container {
background: white;
margin: 0 auto;
border: 1px solid grey;
}
.block {
width: 100%;
height: 100px;
}
.blue {
background: blue;
}
.red {
background: yellow;
}
.transform {
transform: translateY(-200%);
}
<div class="container">
<div class="block red transform"></div>
<div class="block blue"></div>
</div>
In this example, there are two div elements and the upper element was translated vertically so that it is not visible anymore. However, the flow layout remains unchanged and there is no overflow in the document. That is, the result of the transformation is purely visual.
Now, consider a page layout with a wrapper of fixed width, such that the width of the child elements is bounded by the wrapper element. Now add a positioned element that is wider than the wrapper and add an offset (e.g. left). In "narrow enough" windows, the body overflows and we are able to scroll horizontally. However, if we translate the same element and re-center it, the overflow disappears, implying that the transformation is not purely visual.
A demonstration of this effect is shown in the example below. Initially, the offset element is not transformed. You may try resizing your window to see the overflow and then toggle the transformation with the button in the center.
document.getElementById('toggle').addEventListener('click', function(event) {
const blocks = document.querySelectorAll('.block.wide');
for(let i=0;i<blocks.length;i++) {
const block = blocks[i];
block.classList.toggle('transform');
}
});
html, body {
background: #ddd;
}
.container {
background: white;
max-width: 1152px;
margin: 0 auto;
}
.content {
border: 1px solid grey;
}
.block.wide {
background: yellow;
max-width: 1380px;
width: 100vw;
position: relative;
left: 50%;
}
.block.wide.transform {
transform: translateX(-50%);
}
<div class="container">
<div class="content">
<div class="block">
<h1>Lorem ipsum dolor sit amet</h1>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<p><strong>Click the button below to toggle the transform and see the overflow vanish</strong></p>
<button id="toggle">Toggle Transform</button>
</div>
<div class="block wide">
<h1>Lorem ipsum dolor sit amet</h1>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
</div>
</div>
Is this the intended behavior according to the specifications? How do offsets and transformations interact?
In all my test cases, the CSS transform achieves the desired result. However, I feel that I am relying on luck rather than a technical specification.
There's several points to cover here.
From the CSS Transforms spec, Section 3. The Transform Rendering Model says:
For elements whose layout is governed by the CSS box model, the transform property does not affect the flow of the content surrounding the transformed element. However, the extent of the overflow area takes into account transformed elements. This behavior is similar to what happens when elements are offset via relative positioning. Therefore, if the value of the overflow property is scroll or auto, scrollbars will appear as needed to see content that is transformed outside the visible area. Specifically, transforms can extend (but do not shrink) the size of the overflow area, which is computed as the union of the bounds of the elements before and after the application of transforms.
Which means transforms are supposed to affect the overflow and scrolling. However, in your first example, the overflow is to a negative coordinate space, and that overflow is always clipped, so it doesn't generate any new scrollbars.
But your second example, on a direct reading, seems to be in contradiction to the specification, with the transform shrinking the overflow area. What I think is happening here is that position relative shifts, and transforms are, as acknowledged by the quote above, very similar operations, and the transform is undoing the effect of the relative positioning.
In other words, the overflow area is being computed as the union of the bounds of the elements before and after the application of relative positioning and transforms.
Is there elegant solution to hover only for top element, not for underlying; or i should to do this using javascript?
<div class="WithHover1">
<div class="WithHover2">
I am Top and I want to be the only div hightlighted
</div>
I want to be hightlighted too, but I dont want to be hightlighted when the nested one is
</div>
You can't do this in just CSS, yet. The has selector is in draft for level 4/5 (I forget) CSS selectors, which will be awesome.
For now, javascript/jquery would be the easiest and most practical method.
$(".WithHover2").mouseover(function() {
$(".WithHover1").removeClass("highlight");
$(this).addClass("highlight");
});
Here's a CSS3 solution, using the ::after pseudo-element, with a bottom border that overrides the background color of the bottom text.
The negative z-index prevents the border from covering up the text, and overflow: hidden prevents WithHover1 from expanding due to the large border.
It works in IE11 (at least), Chrome, Firefox, Safari, and Opera:
div.WithHover1 {
font: 14px verdana;
position: relative;
overflow: hidden;
}
div.WithHover1:hover {
background: yellow;
position: relative;
z-index: 1;
}
div.WithHover2:hover {
background: orange;
}
div.WithHover2:hover::after {
content: '';
display: block;
position: absolute;
border-bottom: 1000px solid white;
width: 100%;
z-index: -1;
}
<div class="WithHover1">
<div class="WithHover2">
I am Top and I want to be the only div highlighted
</div>
I want to be highlighted too, but I dont want to be highlighted when the nested one is.
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum
</div>
This isn't what you want? Your post wasn't that clear to me what you needed when hovering over each.
.WithHover2:hover, .WithHover3:hover {
background-color: yellow;
}
<div class="WithHover1">
<div class="WithHover2">
I want to be the only div hightlighted
</div>
<div class="WithHover3">
I dont want to be hightlighted when the nested one is
</div>
</div>
I need to make an image auto-fill the width and height of the viewer's screen, while keeping the correct aspect ratio. The ultimate goal is to display a jquery slideshow in the background of the page, while also making it fill the full width and height of the screen.
This jfiddle shows an approximation of what I am talking about: http://jsfiddle.net/hockey2112/s1d2peqh/1/
Here is the CSS from that jfiddle:
#slideshow {
height: auto;
position: fixed;
width: 100%;
z-index: -1;
}
.slide img {
height: auto;
width: 100%;
}
.contentbox {
background-color: #ffffff;
border:5px solid #000000;
margin: 0 auto;
width: 300px;
}
and the code:
<div id="slideshow">
<div class="slide">
<img src="http://www.iapics.org/images/3542-wallpaper-landscape-wallpapers-1920x1080.jpg">
</div>
</div>
<div id="content">
<div class="contentbox">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</div>
</div>
I need the image to fit the height of the screen first, and then show as much of the width of the image as will fit in the screen. If you expand and contract the viewport of that jfiddle, you'll see that the image does not fill the height of the preview panel.
Thanks!
I'm not aware of a way to do this in CSS alone.
You can either have the image stretched to 100% horizontally and centered vertically OR you can stretch 100% vertically and center horizontally.
However, with a little but of js, you can switch between these two options pretty easily, and that should get you what you want.
Horizontal Stretch + Vertical Center:
.slide.horz{
height:100%;
width:100%;
}
.slide.horz img {
width: 100%;
height:auto;
display:block;
margin:auto;
position:absolute; /*trick for vertical center*/
top:0; /*trick for vertical center*/
bottom:0; /*trick for vertical center*/
}
Vertical Stretch + Horizontal Center:
.slide.vert{
height:100%;
width:300%; /* trick for 'zoomed' horizontal center */
margin-left:-100%; /* trick for 'zoomed' horizontal center */
}
.slide.vert img {
height: 100%;
width:auto;
display:block;
margin:auto;
}
Then some jquery will let you switch between the classes based on the aspect ratio of the window.
$(window).resize(function() {
setStyle();
});
function setStyle(){
var winRat=($(window).width() +0.0)/($(window).height() + 0.0);
var imgRat = 1920.0 / 1080.0;
//do vertical stretching
if( winRat < imgRat){
$(".slide").removeClass("horz");
$(".slide").addClass("vert");
}else{
//do horizontal stretching
$(".slide").removeClass("vert");
$(".slide").addClass("horz");
}
}
Have only tested this in latest chrome. I have reason to believe it may break in ie<=8.
http://jsfiddle.net/s1d2peqh/3/
This is the purpose of the VH (viewport height) and VW (viewport width)
body { width:100%;height:100%; }
#slideshow { height: 100vh;position: fixed;width: 100vw;z-index: -1; }
.slide img { height: 100vh;width: 100vw; }
I'm looking for a way to vertically align a block element to an image. On my site this image would dynamically change in height and width so I'd need the vertical alignment to adapt for whatever the image size is. For example:
<img src="photo.jpg" alt="test" />
<div id="box">
</div>
img { float: left; }
#box { float: right; width: 200px; height: 150px; background-color: #666; }
So I'd want this div to vertically align itself to the image. How can this be done?
Thanks.
The trick is to add a couple layers of wrapper-divs. The first layer is set to white-space: nowrap and max-width:50% which means that the elements inside can't wrap, and are constrained to 50% of the width of the parent.
Then you set the white space back to normal, and make the second layer display:inline-block so that these divs have to play by text alignment rules. Then you set both of them to vertical-align:middle; Just one won't work because vertical align is relative to the baseline of the text, not the containing block element.
So in this way we have constrained ourselves to one line of "text", composed of two div elements both aligned such their middle is at the text baseline, and ensured that their size must be no more than 50% of the parent container.
EDIT: I discovered after little more playing that you need to add some max-width:100% to keep the image from pushing the text out the right hand side.
EDIT 2: I should have mentioned that this requires IE-8 standards mode, added meta-equiv to tell IE-8 to behave itself, but giving a proper doctype or sending an http response header can achieve the same thing google IE8 standards mode for all that stuff.
<html >
<head>
<title>Test</title>
<meta http-equiv="X-UA-Compatible" content="IE=8" />
<style type="text/css">
.wrapper1 {
white-space:nowrap;
max-width:50%;
}
.wrapper2 {
white-space:normal;
display:inline-block;
vertical-align:middle;
max-width:100%;
}
.variable-img {
max-width:100%;
}
</style>
</head>
<body>
<div class="wrapper1">
<div class="wrapper2">
<img class="variable-img" src="test.png">
</div>
<div class="wrapper2">
<div id="box">
Lorem ipsum dolor sit amet, consectetur adipisicing elit,
sed do eiusmod tempor incididunt ut labore et dolore magna
aliqua. Ut enim ad minim veniam, quis nostrud exercitation
ullamco laboris nisi ut aliquip ex ea commodo consequat.
Duis aute irure dolor in reprehenderit in voluptate velit
esse cillum dolore eu fugiat nulla pariatur. Excepteur sint
occaecat cupidatat non proident, sunt in culpa qui officia
deserunt mollit anim id est laborum</div>
</div>
</div>
</body>
</html>
See markup + css below, or this fiddle:
http://jsfiddle.net/gq9w6/15/ ... in IE7 (or IE8/9 compatibility view)
The "Lorem ipsum" text should be wrapping around both divs #1 and #3, but in IE7, it clears div #1.
How can I get IE7 to behave in this scenario?
HTML:
<div id="div1">Feature image</div>
<div id="div2">
<div id="div4" class="a">fb like</div>
<div id="div5" class="a">g-plus1</div>
<div id="div5" class="a">tweet</div>
</div>
<div id="div3">related topics list</div>
<div id="div7">bi-line</div>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
CSS:
#div1{border:1px dotted green;float:left;width:100px;height:100px;}
#div2{height:15px;}
#div3{float:right;clear:both;width:100px;height:30px;border:1px dotted green;}
.a{float:left;width:70px;border:1px dotted red;}
#div7{text-align:left;}
UPDATE:
HTML/CSS and fiddle to (/14) all updated with sample text that shows the purpsoe of each div.
UPDATE
Written description of requirements:
A featured image floated to the left
A series of social-media share buttons to the right of the image, in a horizontal row with the top of the row aligned with the top the featured image
a by-line beneath the social-media buttons (they're not wrapping correctly in the fiddle, but never mind, that's easy to fix)
A "related topics" widget floated right, clearing the featured image (top edge of the former aligned with the bottom edge of the latter)
article text beginning beneath the by-line, wrapping around the rest of the featured image as well as the related topics widget
In your code #div1 is floated to the left which takes out of the document flow, leaving #div2 to occupy the space, although the contents is being pushed by the float. Your #div3 is actually clearing all floats and is floated to the right (it's the reason it's on the same level as the bottom of #div1. Not sure what #div7 is doing. Is it also supposed to float?
What are you trying to achieve?
If you add float: left to #div2 and #div7 and remove clear: both from #div3 you will get the same result in all browsers.