Table cell width declaration is ignored - css

I have an horizontal menu bar that can have from 1 to 4 links.
I would like that that each link will have a width of 25% not depending by number of them (so in case of only 3 links, menu bar should be only 75% of another one with 4 links).
Using floats reach the target but in case of longer text spanned across 2 rows, is not possible to adjust other links' height accordingly, so I use display:table-cell that solve this issue, but in case of 3 links, completely ignore width:25% and it renders like if width would be 33%.
<div class="container">
<div class="block">
Link 1
</div>
<div class="block">
Link 2
</div>
<div class="block">
<a href="#">
Link 3 with very long text tha span across 2 rows
</a>
</div>
</div>
.container {
display: table;
width: 100%;
border:solid 1px blue;
}
.block {
border: 1px solid red;
display: table-cell;
width: 25%;
}
Please, look at this jsFiddle in order to see both cases.
Desired result is that second menubar links continue to have the same width of first one, not becoming 33%.
I tried also to add table-layout:fixed as read in other threads but was unuseful
How to solve this?

When you ask a browser to display a three-column table so that the width of each column is 25% of the total width, you are making a logically impossible request. You cannot have the width of a table to be 75% of itself. Browsers then tend to divide the space evenly to the columns.
A simple fix is to remove width: 100% from the rule for .container and to set width: 75% on the second “table” (div element formatted as a table).

How about using flexbox?
.container {
display: -webkit-box; /* OLD - iOS 6-, Safari 3.1-6 */
display: -moz-box; /* OLD - Firefox 19- (buggy but mostly works) */
display: -ms-flexbox; /* TWEENER - IE 10 */
display: -webkit-flex; /* NEW - Chrome */
display: flex; /* NEW, Spec - Opera 12.1, Firefox 20+ */
border:solid 1px blue;
}
.block {
border: 1px solid red;
max-width: 25%;
-webkit-box-flex: 1; /* OLD - iOS 6-, Safari 3.1-6 */
-moz-box-flex: 1; /* OLD - Firefox 19- */
-webkit-flex: 1; /* Chrome */
-ms-flex: 1; /* IE 10 */
flex: 1; /* NEW, Spec - Opera 12.1, Firefox 20+ */
-webkit-box-sizing: border-box; /* Safari/Chrome, other WebKit */
-moz-box-sizing: border-box; /* Firefox, other Gecko */
box-sizing: border-box; /* Opera/IE 8+ */
}
a{
display: block;
padding: 10px;
}
In this way you can easily adjust your .block element's height accordingly...
here's a fiddle with my solution: http://jsfiddle.net/o462q4ce/

Please check this.
var n = $(".container .block").length;
var w = (100/n);
$(".container .block").width(w+'%');
See jsFiddle. Hope it helps.

Using a combination of :last-child and :nth-child() selector you can target exactly the div.block you need to modify.
Unfortunately using table layout doesn't allow you to manage margin and width as I wish...
anyway here is a solution could fit for your needs
.block:last-child:nth-child(3) {width:auto; padding-right:25%;}
.block:last-child:nth-child(2) {width:auto; padding-right:50%;}
.block:last-child:nth-child(1) {width:auto; padding-right:75%;}
in this jsFiddle you can see these selectors in action: http://jsfiddle.net/5t0fq1sy/

Related

CSS3 flexbox layout with ellipsis doesn't work on mobile Safari

The following demo (submitted as an SO answer) illustrates usage of ellipsis with flexbox layout. However, it doesn't seem to work on mobile Safari - the text is not shortened at all (tested on iPhone 5, iPhone X and iOS 11.4 emulator in XCode). It works on all desktop browsers including Safari.
http://jsfiddle.net/Blender/kXMz7/1/
.parent-div {
display: -webkit-flex;
display: -moz-flex;
display: flex;
}
.text-div {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
min-width: 0;
}
.icon-div {
-webkit-flex: 1;
-moz-flex: 1;
flex: 1;
}
<div class="parent-div">
<div class="icon-div">X</div>
<div class="text-div">This is text I'd like to truncate when space doesn't permit</div>
</div>
Is this a known problem?
https://www.w3schools.com/css/tryit.asp?filename=trycss3_text-overflow, sets width to truncate the characters when the given width isn't enough.
Although while using flex, setting 'width' is not recommended. I just added flex-basis: 40%; in 'text-div' class and I could see the truncation happening.

Make the code-mirror block fill the rest of the page in Safari

I want to make a page that satisfies the following conditions:
it contains some texts in the first part and a
code-mirror in the second part
the texts in the first part are almost fixed (so their height is almost fixed), and I want the height of the code-mirror to fill exactly the rest of the page. If there are many texts in the code-mirror, then use scroll.
Then, I make this plunker:
<style>
.rb {
display: flex;
flex-direction: column;
height: 100%;
}
.rb .CodeMirror {
flex: 1;
}
</style>
<div class="rb">
1<br/>2<br/>3<br/>4<br/>
<textarea ng-model="body" ui-codemirror="option"></textarea>
</div>
It works perfectly in Chrome, it however does not work in Safari: the height of the code-mirror is incorrect; we see immediately the problem:
Does anyone know how to fix this? I used to have a solution with calc(minus a fixed px), but I cannot find it anymore.
Why don't you use height: 100% instead of flex: 1?
.rb .CodeMirror {
height: 100%;
}
Update:
For the sake of future users, the above didn't work, but with calc it did for both Safari and Chrome, so:
.rb .CodeMirror {
calc(100% - 80px); /* notice the spaces around "-" */
}
where 80px is the height of the "first part" as described in the original post.
Plunker
It would like to give question a try.
You may want to use em instead of vh.
1em = approx 16px
Also from what I read from w3schools: https://www.w3schools.com/cssref/css3_pr_flex.asp
You will need to also import the browser property. I am guessing the correction should be:
<style>
// just in case you didn't
<!--
html,body{
height: 100%; // or 100vh
}
-->
.rb {
display: -webkit-flex; // for Safari
display: flex;
-webkit-flex-direction: column;
flex-direction: column;
// remove this height: 100%;
// otherwise should set 100vh to height
}
.rb .CodeMirror {
// You may want to try auto instead of 1.
// As the size of the chrome for each browser is different.
-webkit-flex: 1; // for Safari
-ms-flex: 1; // for IE
flex: 1;
}
</style>
<div class="rb">
1<br/>2<br/>3<br/>4<br/>
<textarea ng-model="body" ui-codemirror="option"></textarea>
</div>
Please let me know if it works or not. thanks!

Implementing a "Mondrian" pattern using Flexbox

The article 5 Really Useful Responsive Web Design Patterns describes a "Mondrian" pattern for layout on the web that arranges one large box on the left (2/3 or 3/4 width) with a few smaller items, stacked vertically on the right — but then in medium-sized viewports, the design shifts to show the main box at full width, with the other boxes side-by-side, horizontally below. (And on small screens, everything is 100% width stacked vertically.)
I have this pattern implemented using floating divs, but I would like to get this implemented using flexbox, so that the boxes can be of equal height no matter what. That's what flexbox is so good at!
Conceptually, I think that this can work, but I am just not having any luck at all with this. I'm surprised that I haven't found any references to this (except for a jsfiddle that's not really what I'm looking for at all.)
I believe that this could be implemented with column wrapping, and the first item's flex basis fairly large so that it takes up all of the vertical space on larger viewports, with the remaining boxes wrapped into a second column, stacking vertically. Using a media query, I think you could then just change the flex-wrap to be row-based so that the remaining smaller boxes get arranged side-by-side below the main full-width image.
And yet, I get nothing. No point even linking to my CodePen work in progress because it's just so pathetic. :-)
Anybody who is super-flexy interested in showing how this might be done?
/* ┌──────────────────────────────────────────────┐
│ These values determine when to switch layout │
└──────────────────────────────────────────────┘ */
.big {
flex-basis: 600px;
}
.outer.flex, .small {
min-width: 300px;
}
/* ┌───────────────────────────────┐
│ This other code makes it work │
└───────────────────────────────┘ */
html, body, .outer.flex {
margin: 0; /* Remove margins */
height: 100%; /* Fill all window */
}
.flex {
display: flex; /* Magic begins */
flex-wrap: wrap; /* Multiline */
}
.big, .small {
overflow: auto; /* In case the content doesn't fit */
box-sizing: border-box; /* Desirable if you want border or paddin */
border: 3px solid; /* Optional */
}
.big {
flex-grow: 2; /* Grow to fill available space, with factor 2 */
min-height: 50%; /* At least 50%, and allow 100% */
background: red; /* Optional */
}
.inner.flex {
flex: 1; /* Grow to fill available space, with factor 1 */
min-width: 33vw; /* At least 33% of the width of the window */
min-height: 50%; /* At least 50%, and allow 100% */
}
.small {
flex: 1 33vw; /* Grow to fill available space, with factor 1 */
/* At least 33% of the width of the window */
background: blue; /* Optional */
}
.small:first-child {
background: green; /* Optional */
}
<div class="outer flex">
<div class="big"></div>
<div class="inner flex">
<div class="small"></div>
<div class="small"></div>
</div>
</div>

Make second div appear above first, without absolute position or changing html

My page is split into 3 slices, as shown in this JFiddle.
In my full source code, I have media queries to help manage sizing between mobile and desktop. When someone accesses the site on mobile mode, Logo should appear at the top, and Items should appear below it. (I set display: none on my picture div to hide it)
Problem:
I can't change the positioning of the divs in HTML, or it'll disturb my current 3 slice layout. Absolute positioning is not an option, since most of my site is already dynamically sized, and I wouldn't want absolute positioning to interfere on a resolution I haven't tested on. This means calculating the margin sizes would be out of the question aswell.
So, absolute positioning is not allowed, nor is changing the orders of the divs. The result I'm looking for would be similar to this, exception without repositioning the divs.
My question is not about media queries, or how to size for mobile using media queries. I am only asking about how to get the layout I want with the restrictions in place (no absolute positing, no calculating margins, no changing div order).
Other questions I looked at:
Reposition div above preceding element - First answer suggests repositioning divs, which I cannot do. Second answer relies on calculating the position, which could interfere with other dynamically sizing elements.
Move The First Div Appear Under the Second One in CSS - Suggests I use absolute positioning, which I cannot do
Flexbox layout is your friend here. display: flex can be used to interchange the elements position on the layout.
#container { display:flex; flex-direction: column; text-align:center;}
#items { order: 2 }
#logo { order: 1 }
#picture { display: none; }
<div id="container">
<div id="items">Items</div>
<div id="logo">Logo</div>
<div id="picture">Picture</div>
</div>
display: flex works only in modern browsers. Check caniuse.
A test on my android mobile shows it working on Firefox and Chrome, but not on the stock Android browser.
I tried to solve the solution using transform: translateY property in percentage value.
Note: This works if and only if the two containers have same height. or if the height is already known, then you can set the transform: translateY value according to the height.
CSS
#media (max-width: 700px) {
#container > div {
width: auto;
display: block;
float: none;
}
#container #picture {
display: none;
}
#logo {
transform: translateY(-100%);
}
#items {
transform: translateY(100%);
}
}
Working Fiddle
Probably the easiest is if you play with minus margins. Note that the below sizes (width and side margins) may need to be adjusted to your specific needs.
#container * {
width: 95vw;
text-align: center;
}
#items {
width: 50%; /* #picture is hidden so we split the screen into 2 */
float: left;
margin-top:30px; /* has to be smaller than the absolute of #logo */
margin-left:25%; /* half of the element's width */
}
#logo {
width: 50%; /* #picture is hidden so we split the screen into 2 */
float: right;
margin-top:-40px; /* its absolute has to be greater than the one of #items */
margin-right:25%; /* half of the element's width */
}
#picture {
width: 33%;
float: right;
display:none; /* Hiding #picture as you said you would */
}
<div id="container">
<div id="items">Items</div>
<div id="logo">Logo</div>
<div id="picture">Picture</div>
</div>

Add padding without changing overall width

How can I add padding to an element without adding on top of the predefined width?
It's good to define the width of a column to make a clean grid for the layout; but also wants to add padding to the contents inside the column. Any way to specify that?
element {
-webkit-box-sizing: border-box; /* Safari/Chrome, other WebKit */
-moz-box-sizing: border-box; /* Firefox, other Gecko */
box-sizing: border-box; /* Opera/IE 8+ */
}
Use box-sizing, it makes padding inclusive:
https://developer.mozilla.org/en-US/docs/CSS/box-sizing
Example:
div {
box-sizing:border-box;
-moz-box-sizing:border-box; /* Firefox */
-webkit-box-sizing:border-box; /* Safari */
}
It's worth noting that this won't work on IE7.
For IE8, please see the top answer to this Q: box-sizing: border-box => for IE8?
Everytime you add padding to block element, the width of this element changes. This problem has many solutions. I usually set margin to first child element and set width: 100% for this element.
For example, we have:
<div id="main">
<div id="child">
This is content with margin
</div>
</div>
CSS style for these elements:
#main {
border: solid 1px red;
float: left;
width: 5em;
}
#child {
border: solid 1px blue;
float: left;
width: 100%;
margin: 0.5em;
}
This is a solution for any browser
It's an old thread, I know. But last time I had a complete black hole about making a DIV with a NOT set width and with paddings, so it will not blow up my 3-columns row and with CSS2. So I put one DIV with float left, on with right and between them a DIV with no float and no fixed width, but I wanted to have padding in it. How about that...
I gived up. :D But I put an inner DIV in the center one and give it width=90%. So far so good, a very simple and not great solution, but sometimes it helps to achieve the look you need. ;]
b.r.

Resources