Equal height table cells with a canvas inside: padding bug? - html

We have a fix set of CSS rules, but when we modify the HTML markup to include a canvas, a weird padding appears on the neighboring cell. Here is the CSS:
.wrap{
width:100%;
display: table;
}
.row {
display: table-row;
}
.left{
width: 100px;
display: table-cell;
background-color: #0f0;
}
.right{
background-color: #f00;
display: table-cell;
}
Normal case:
See the fiddle here. Note the position of the text in the red cell: top, aligned with the top of the cell.
<div class="wrap">
<div class="row">
<div class="left">
Lorem<br>Lorem<br>Lorem<br>Lorem<br>Lorem
</div>
<div class="right">
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
</div>
</div>
</div>
Canvas case:
See the fiddle here. We swapped the Lorem text in the left cell for a 90x90 canvas. See how the text on the red cell is now aligned with the bottom of the canvas and a padding is applied to the cell.
<div class="wrap">
<div class="row">
<div class="left">
<canvas width='90px' height='90x'></canvas>
</div>
<div class="right">
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
</div>
</div>
</div>
Question: Could you explain why this padding appears on the left cell, and if this is an expected behavior? Also, could you propose a solution that gets rid of this 'bug'?

Related

Using <p> with left floating divs causes second div to go below first div

https://jsfiddle.net/9nh220q2/1/
Basically, I have something like this:
<div class="container">
<div class="left">
<img src="http://i.imgur.com/bWQUX0O.jpg" class="image" />
<span>0.3 mi</span>
</div>
<div class="right">
<h3>TITLE HERE</h3>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum nec turpis eu mi nullam sodales.</p>
</div>
</div>
However, these items are inside of a scrolling panel. So, in the jsFiddle I have put these inside of a parent div with width of 600px. As you can see, the <div class="right"> is going below. How can I stop it from doing that?
Calculated width of .right
.right {
width: calc(100% - 120px);
}
.container {
background-color: #fff;
padding: 20px 20px 10px 20px;
overflow: hidden;
border-bottom: 1px solid lightgray;
margin: 0;
}
.left {
width: 100px;
float: left;
margin: 0;
text-align: center;
}
.image {
height: 100px;
width: 100px;
border-radius: 4px;
margin-bottom: 5px;
}
.right {
float: left;
padding-left: 20px;
width: calc(100% - 100px - 20px); /* all width - size of image - padding) */
}
h3 {
margin: 0;
}
<div style="width: 600px">
<div class="container">
<div class="left">
<img src="http://i.imgur.com/bWQUX0O.jpg" class="image" />
<span>0.3 mi</span>
</div>
<div class="right">
<h3>TITLE HERE</h3>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum nec turpis eu mi nullam sodales.</p>
</div>
</div>
<div class="container">
<div class="left">
<img src="http://i.imgur.com/bWQUX0O.jpg" class="image" />
<span>0.3 mi</span>
</div>
<div class="right">
<h3>TITLE HERE</h3>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum nec turpis eu mi nullam sodales.</p>
</div>
</div>
<div class="container">
<div class="left">
<img src="http://i.imgur.com/bWQUX0O.jpg" class="image" />
<span>0.3 mi</span>
</div>
<div class="right">
<h3>TITLE HERE</h3>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum nec turpis eu mi nullam sodales.</p>
</div>
</div>
</div>
You can fix this by removing all float and using flexbox. Flexbox is a powerful modern way to handle this kind of layout. flexboxfroggy is a great way to learn about them.
.container {
display: flex;
justify-content:space-between;
}
Demo
An even better way would be to use standard css grid, but we should wait a bit more.
Edit:
All modern browser support flexbox. For old one, you can use a polyfill if you have to.
You need to set the width of .right to a maximum of 440px. See the working fiddle.
Explanation:
Your container div has a width of 600px. For the elements contained within to line up properly, their widths must add up to a maximum of 600px.
Your img already takes up 100px of that. That means that your div.right can have a maximum width of 500px. (Because 600px - 100px = 500px)
However, if you do set it at 500px, you'll most likely notice that the issue won't be solved. This happens because, by default, most (if not all) browsers render the page using the content-box model which includes the padding and margins of the elements when calculating their widths.
In your case, your containing div has 20px of padding in both sides. In addition, your div.right has 20px of padding on the left. This adds up to 60px which you need to subtract from your available space that we calculated above, 500px. That leaves you with 440px and if you set that as the width of div.right, you'll notice that the elements line up perfectly!
You can also change the default way in which the browser sees the box model by changing the value of box-sizing from content-box to border-box (neither padding nor margins are not calculated in width) or to padding-box (padding is not calculated in width) and then adjust padding, border or width values accordingly.

2nd "display:table" inside "display: table-cell" sets unwanted margin-top

This image shows desired layout:
"Lorem ipsum" div is placed on top and "Dolor sit" div sits under it. Right "P" div sets minimal height (first part) of whole main wrapper section unless "Dolor sit" div increases height (second part).
Implementation is shown in this Plunker:
Plunker demonstration
<section id="wrapperMain" style="display:table; width:100%">
<div style="background-color:#2e3338; display: table-cell; min-width:50px; width:50px;">
<h1 style="margin-left:25%; margin-right:25%">P</h1>
</div>
<div style="background-color:dodgerblue; display: table-cell;">
<!--This section should fill its parent: dodgerblue div-->
<!--So no blue color could be seen above "Lorem ipsum" div-->
<section style="display:table; width:100%; background-color:crimson; margin-top:0;">
<div style="display:table-row">
<div style="background-color:darkslategray;">Lorem ipsum</div>
</div>
<div style="background-color: #1c1e22; border-style: none; resize: none; width: 100%;">Dolor sit Dolor sit Dolor sit Dolor sit Dolor sit Dolor sit </div>
</section>
</div>
And with any combination of setting margins, heights, displays I wasn't able to dock 2nd table section inside table cell without margin on top. Right now I'm not sure if this is correct approach.
I think this is what you are after, you just need to add vertical-align:top to the table cell on the right
I have also fixed your second table styles as you had block mixed with table-rows and no table-cells which may cause issues for some browsers:
<section id="wrapperMain" style="display:table; width:100%">
<div style="background-color:#2e3338; display: table-cell; min-width:50px; width:50px;">
<h1 style="margin-left:25%; margin-right:25%">P</h1>
</div>
<div style="background-color:dodgerblue; display: table-cell; vertical-align:top"> <!-- add vertical align:top here -->
<!--This section should fill its parent: dodgerblue div-->
<!--So no blue color could be seen above "Lorem ipsum" div-->
<section style="display:table; width:100%; background-color:crimson; margin-top:0;">
<div style="display:table-row">
<div style="background-color:darkslategray; display:table-cell">Lorem ipsum</div>
</div>
<div style="background-color: #1c1e22; border-style: none; resize: none; width: 100%;display:table-row;">
<div class="display:table-cell">Dolor sit Dolor sit Dolor sit Dolor sit Dolor sit Dolor sit</div>
</div>
</section>
</div>
</section>

Background color/image of div expand the whole page, but content stays in wrapper

This seems so trivial, but how do I make the background color or image of a div span the whole window, but keep the content in a wrapper or set width? Almost like a footer, or nav.
Like on this page in the footer, the gray and the lack parts go the whole across the page but any type is still in a set width that matches the rest of the page. Some pages have these in the middle and divide their whole page using this technique.
Thanks for any help!
For a content wrapper, make the wrapper div fixed width and use margin: 0 auto to center it horizontally - http://codepen.io/anon/pen/kwebf
<style type="text/css">
body {
background: #ff0000;
}
div {
margin: 0 auto;
width: 500px;
}
</style>
<body>
<div>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
</div>
</body>
For fixed width content without a wrapper, put horizontal padding on your body - http://codepen.io/anon/pen/hoKdk
<style type="text/css">
body {
padding: 0 200px;
background: #ff0000;
}
</style>
<body>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
</body>
you could either wrap each section in an element (A) just to span across the page and prodive the background, and wrap the content in an element (B) to center it in A. like this:
<div id="main-wrap">
<div class="content">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
</div>
</div>
<div id="footer-wrap">
<div class="content">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
</div>
</div>
<style>
#main-wrap {
background:red;
}
#footer-wrap {
background:green;
}
.content {
width:300px;
margin:0 auto;
}
</style>
or you could use an advanced solution similar to this one.
it really depends on your design and requirments

CSS for a text container between min and max width

How can I style a DIV with text in it so that if takes the minimum length between a min-width and a max-width?
For example, if I have the min and max set at 200 and 400px, I want:
a div with text shorter than 200px to be 200px wide
a div with text between 200px and 400px to have the width of the text
a div with text longer than 400px to be wrapped
This jsFiddle I made explains it better: http://jsfiddle.net/LHFSn/ ...it sounds simple and straight forward but I just can't seem to figure it out.
And no, the obvious:
min-width: 200px;
max-width: 400px;
...doesn't give me what I want at all.
Setting
display: inline-block
will allow you to achieve the desired result width-wise, but will also mean the elements will be displayed inline, that is, next to one another if they fit.
You can avoid this by wrapping your elements in block-style containers. While this sounds far from ideal it's the first idea off the top of my head that works.
Expanding on your further question, you can float these elements, wrap them in a container that's also displayed inline and then block it using RĂșnar Berg's suggestion of empty blocks.
See sample jsFiddle
Clearfix reference
HTML:
ACTUAL:
<div></div>
<div class="wrapper cf">
<div class="flex-text">
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor.
</div>
<div class="flex-text">
Lorem ipsum dolor sit amet.
</div>
<div class="flex-text">
Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
</div>
</div>
<div></div>
Further content
CSS:
.flex-text {
min-width: 200px;
max-width: 400px;
display: inline-block;
background: #def;
float: left;
clear: both;
}
/* this is just to show a 200px ruler for reference */
.flex-text:after {
content: "";
display: block;
width: 200px;
border-top: 4px solid black;
margin: 0 0 20px 0;
}
.wrapper {
display: inline-block;
background: lightblue;
}
.cf:before,
.cf:after {
content: " "; /* 1 */
display: table; /* 2 */
}
.cf:after {
clear: both;
}
.cf {
*zoom: 1;
}
You can try to set the container display to table and the inner display to table-cell.
It might get you into more trouble though.
http://jsfiddle.net/fXxV3/3/
Problem:
Your .flex-text is a non-floated block element so by default it fills the width of its parent. In this case, max-width means if your parent is larger then take on the max-width and if your parent is smaller than min-width then take that value.
On the other hand, a floated block element with no width set will shrink to the size of its contents.
Solution:
You basically have to move your min/max width to an outer wrapper div which is not floated as you did, and then float the inner flex-text inside so that the background will only fill the area containing text:
So your markup becomes:
<div class="wrapper">
<div class="flex-text clearfix">
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor.
</div>
</div>
<div class="wrapper">
<div class="flex-text clearfix">
Lorem ipsum dolor sit amet.
</div>
</div>
<div class="wrapper">
<div class="flex-text clearfix">
Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
</div>
</div>
So your css becomes:
.wrapper{
min-width: 200px;
max-width: 400px;
}
.flex-text {
background: #def;
float:left;
}
Also, since you are floating .flex-text, make sure to add a clearfix.
DEMO

Float element mystery

I have the following markup:
<div id="container">
<div id="sidebar">
<h2>Sidebar</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod</p>
</div>
<div id="main">
<h2>Main</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod</p>
</div>
</div>
And following styles:
#sidebar {
background: #e3e3e3;
float: left;
}
#main {
background: #666;
}
I was expecting div with id sidebar to go on top and hide div with id main. My logic is - div with id sidebar is floated and is removed from normal flow thus div with id main should take its position. But all browsers display div with id main right below div with id sidebar as if there was no float.
You need to clear float after #sidebar.
HTML:
<div id="sidebar">
....
</div>
<div class="clr"></div>
<div id="main">
....
</div>
CSS:
.clr{clear:both;}
DEMO here.