This question already has answers here:
Make container shrink-to-fit child elements as they wrap
(4 answers)
Closed 5 months ago.
I'm playing with flexbox system in CSS and I can't figure out how to solve my problem.
If I have box with long text, which breaks to two lines, box grows to full width available and I don't want that. If text is on many lines then I want box to grow to width of the longest line. Well, my english is not so good that's why I have images to better show what I want to achieve.
This is what I have now:
And this is what I want to have:
I looked for ready solution in google (and stackoverflow) but without luck.
I prepared also JSFiddle for that: http://jsfiddle.net/f98VN/4/
Is it possible to do what I want and if yes then how can I achieve that? If not, what are your suggestions?
Code:
HTML
<div class="flex-parent">
<div class="item1"></div>
<div class="item2">text is here</div>
<div class="item1"></div>
</div>
CSS
.flex-parent {
display: flex;
justify-content: center;
width: 550px; /* it has width of the whole page, in fiddle I changed it to fixed */
align-items: center;
}
.item1 {
background: red;
height: 100px; /* it has constant width */
width: 100px;
}
.item2 { /* it's width is fluid, depends on text inside which is modified by JS */
background: pink;
font-size: 100px;
}
You may shrink middle container to the longest word using :display:table;width:1%; DEMO or use inline-block and inline-table, dropping the flexmodel : DEMO (this is it)
To keep words together you may use a non breaking character in between words you want to keep aside on same line : DEMO
Edit:
Above demos works in some browsers. In Chrome and Opera content moves to the side of the page.
Fixed version: http://codepen.io/gc-nomade/pen/izKFG
Well, the extra space appears because the whitespace break is a fake effect applied by the browser. What in fact happens, and it's hidden by the browser, is that the word is breaking between its letters, then the extra-space is actually the space that the letters really take.
You can see it by setting the text div to word-break: break-all; http://jsfiddle.net/f98VN/10/
It's not the effect you asked, but at least it doesn't leave extra space.
I got it to appear the way you want using percentages not fixed pixel width,
changed width: 550px; to width:70%;
check out this Updated fiddle
Related
I'm using a grid layout consisting of two div elements with the following column template:
fit-content(25%) auto.
I want to have the first div as high as the grid height with a vertically written and centered text in it.
I also want the first div to contain a fieldset, thus I set display: flex and align-items: stretch on the fieldset so the contained items have the maximum available height.
I set up the following example:
div#grid {
display: grid;
grid-template-columns: fit-content(25%) auto;
}
div#first-column > fieldset {
display: flex;
align-items: stretch;
height: 100%;
box-sizing: border-box;
}
div#sideways {
writing-mode: tb-rl;
transform: rotate(0.5turn);
text-align: center;
}
<div id="grid">
<div id="first-column">
<fieldset>
<div id="sideways">
Sideway Text
</div>
</fieldset>
</div>
<div id="second-column">
text<br/>
to<br/>
make<br/>
the<br/>
grid<br/>
higher<br/>
<br/>
<br/>
</div>
</div>
As you can see, the vertical text in the first grid column is out of bounds.
When re-enabling the text-align: center property in firefox using the css debugger the text gets rendered correctly.
In chrome the layout changes when re-enabling the box-sizing property.
See the following video:
https://screens.totally.rip/2018/09/vokoscreen-2018-09-25_23-33-02.webm
My guess is that the browser fails to calculate the width of the first grid column because the text is written vertically.
But maybe I'm just not using some css properties correctly.
If you want the first-column to take up the all width ..try
flex:1;
In the first-Column div.
But if you want the .first-column
To be on the left side as in asidebar
Set the grid-area and define each then apply to the divs
.grid {display:grid;
grid-template-column: ...
grid'template-row:....
grid-area:
"first first second"
"first first second"}
.first-column {grid-area:first}
.Second-column:{grid-area:second}
that is : if you wanted two vertical columns , first bigger than second column
notice :have used class (.)but don't mind am typing using ma phone , so it kinda sucks just use your number sign
I reported the bug and it turns out that this is already known. Apparently the child fails to report the correct width because of the orthogonal flow.
See my bug report and the underlying issue.
I haven't been able to find a chromium issue for this behavior, but I guess the bug is also already known there.
Note that the firefox and chromium bugs are actually not the same.
The minimal test case I provided with my bug report renders fine in chromium, but the example from my question above doesn't. I guess it has something to do with the flex layout.
A JSFiddle of it: http://jsfiddle.net/24tL8mkq/3/
I want the red highlighting to continue all the way across the box.
Right now, it's set-up such that:
<div style='width: 500px; overflow: auto; border: 1px solid black; padding-top:-5px;'>
<pre id='pre_1'>
<!-- code box -->
</pre>
</div>
with the relevant css (this is the CSS that I want to extend across the entire div, through the overflow) being:
.bad {
background-color: palevioletred;
width: 100%;
}
I get that I can't use width: 100% as that'll only extend to the right most side of the overflow always, but I can't set a static width as I don't know what the size of the box could be.
I'd really prefer to keep this a HTML/CSS solution if possible just to make this as portable as possible.
Interesting problem. The following works for me in the latest Firefox, Chrome and IE11, though I'd consider this somewhat "experimental" - definitely should be further tested if you need to support a broader range of browsers.
http://jsfiddle.net/24tL8mkq/5/
pre {
display: table;
}
pre > div { display: flex; }
I wish I could tell you why this works, but I don't know. I wasn't able to find another combination that works, however. My guess: setting the pre to display: table makes it so the width will go wider than 100% (500px), as tables will do (when their children are wider than the table). Setting flex on the div children is filling the available space since all the children should be equal width.
I'm more of a designer than a coder, so apologies if this question seems bone-headed and the answer obvious.
Anyway, with that caveat out of the way... I'm trying to create a page where the images are in a row that extend off the right edge of the screen, so that the user can scroll to see more images. Other interface elements like the logo and nav are fixed in place.
You can see the page here: http://werewolf.phantomlimb.net/
and the CSS here: http://werewolf.phantomlimb.net/wolf.css
To remove the spaces between the images I have floated them left.
My question is that in order to prevent the images from wrapping, even with a height attribute on the container div and display: block I have to give the div a width value, in this case 4000px. A width of auto for example makes the images wrap onto a new line, which is what I don't want!
As I may not always know the exact width of the combined images, is there a width value I can use that will force the images to stay in a single row, or some other CSS trick?
Many thanks.
J
I would use inline-block for this kind of stuff.
Something like this:
#imgHolder{
font-size: 0px; /* Remove the spaces between the images */
white-space: nowrap; /* Prevent the images from wrapping */
}
#imgHolder img{
display: inline-block;
vertical-align: top;
height: 654px;
width: auto;
}
Here's a working example:
http://jsfiddle.net/155ukfwp/
I've got the following layout:
<article>
<h3><a>...</a></h3>
<h3><a>...</a></h3>
</article>
The first header has dynamic content, the second has a fixed width set.
I'd like the headers to be inline, and when the content of the first one grows, for it to stretch until the sum of both headers' widths is 100%, and then for overflow text to be ellipsis.
I've been running into the problem of once I make the first div inline or float, its width no longer stays contained by the parent, making text overflow everywhere, or with overflow set to hidden, I can't get the second header to be positioned on the same line with it.
P.S.: Unfortunately this will need to support as many old browsers as possible, back to I.E. 6 would be the best (/barf) but whichever solution reaches as far back as possible will be the most valuable. Thanks you!
If I understood the question right, it's easily achievable with flexible boxes:
article {
display: inline-flex;
width: 100%;
}
article > h3:nth-child(1) {
flex: 1;
}
article > h3:nth-child(2) {
flex: 0 0 150px;
}
a {
width: 100%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
display: inline-block;
}
JSBin.
If I'm understanding the issue properly, the following JSFiddle may have the solution:
http://jsfiddle.net/modenadude/QntUm/2/
The code:
keeps the two <h2>s inline
if the width of the first <h2> gets wider than the width of the second <h2> + <article>'s width, it adds the ellipses to the first <h2>
I set max-width on the <h2>s (to 50%) just in case, and added outline to show the widths clearly.
I used jQuery to figure out the widths of the <h2>s onload, but the same can be done with pure JS by using getElementByID (I can set that up too if you'd like). And of course it was designed to be used on only two <h2>s and one <article> so simple editing could make it more expandable.
My problem is with the header. So I basically have 3 columns of divs. I want the middle one to have a constant width of 980px, and then I want the left of the header to extend to the end of the browser window with a blue background color. As for the right of the header, I want that to extend to the end of right side of the browser with a black background color. It kind off looks like this:
<------------------------------[blue][center header][black]---------------------------->
I've done my research and all I could find so far are two columns with a fixed left column with the right column filling up the rest of the space. I wonder how this can be applied to my problem?
Would it be like:
<div style="width:100%;">
<div style="display:table-cell; background-color:blue;"></div>
<div style="width: 980px;">my header</div>
<div style="display:table-cell; background-color:black;"></div>
</div>
Thank you!
A simple solution - basicaly using your exact stying, but putting another block in the central table-cell element, something like this span here:
<div class="wrapper">
<div class="left"></div>
<div class="center"><span>my header</span></div>
<div class="right"></div>
</div>
I moved all the inline style to a separate CSS block and used class selectors:
.wrapper {
display:table;
width:100%;
}
.left {
display:table-cell;
width:50%;
background-color:blue;
}
.right {
display:table-cell;
width:50%;
background-color:black;
}
.center {
display:table-cell;
}
.center span {
display:inline-block;
width:900px;
}
here is a jsfiddle
and here I made the center much narrower for a better illustration: jsfiddle
Hope this helps =)
Unfortunately there isn't a super smooth way of doing this that is also has wide cross compatibility support. There is a CSS spec for display called flex or flexbox which would do what you want beautifully and elegantly, but it has very limited support at the moment. Here is some resources on flexbox for your perusal...
http://css-tricks.com/old-flexbox-and-new-flexbox/
In the meantime, you can achieve the layout you want with some basic CSS jiggery-pokery that will get you what you want, but it requires absolute positioning your middle div.
Heres the JSFiddle: http://jsfiddle.net/CW5dW/
Here's the CSS:
.left {
width: 50%;
height: 300px;
float: left;
padding-right: 160px;
box-sizing: border-box;
background: red;
}
.right {
width: 50%;
height: 300px;
float: right;
padding-left: 160px;
box-sizing: border-box;
background: blue;
}
.middle {
position: absolute;
width: 300px;
height: 300px;
left: 50%;
padding: 10px;
margin-left: -150px;
box-sizing: border-box;
background: orange;
}
What is going on here you might ask?
Basically, we are taking the div with class middle and removing it from the flow of the document. This allows us to float our left div left, and our right div right, with widths of 50% in order to fluidly take up ALL space of the browser.
We then tell the middle div to take up 300px of space (in your case 980), and we tell it to go 50% of the total width of your browser from the left. This doesn't center it though, because its calculated from the left edge of your div. So we give it a negative margin space of half it's width, to sort of "move" that left edge to the center of the div.
Then, since we know the middle div has a width of 300px (in your case 980), we can then say that the left div should have some padding on its right edge greater than or equal to half the middle divs width, in my example that's 150px, and I added 10px more so text couldn't come right to the edge of the div, so 160px total. We do the same for the right div but for it's left side. This limits the content of those two divs from falling underneath our middle div.
This answer is not an "answer" as such - it's an extended comment to #Michael's post. I have, however, posted another answer - a jQuery solution.
Regarding #Michael's answer (which is a very tidy solution indeed) there is a tiny issue that if you remove your height declaration (which the OP undoubtedly will) then the backgrounds for the various columns become exposed - this method relies on the backgrounds all levelling out at their bottom edge in order to make the design coherent. If the OP's design doesn't have backgrounds behind the columns then this solution should be fine. If backgrounds are required (which they might be judging by the question wording) then it could be awkward. Two solutions to this...
a simple javascript that scans the page for column length, finds the longest, and matches all shorter ones to the maximum.
The other (and probably better) solution is to drop a background into your with the columns already on it (it only needs to be 1px high I guess) - just make sure the central white band is 980px wide and the side columns extend off a thousand or so pixels to accommodate even the largest of browsers
OK, here's my solution. This will present a "common or garden" three column fixed width layout to all users and then adjust it for users with javascript enabled (which, let's face it, is the vast majority of users). The benefits of this solution are that the layout will behave like any ordinary 3 solumn layout without the quirks you can experience from using more advanced CSS tweaks like absolute positioning and fixed heights.
Fiddle here... http://jsfiddle.net/vuary/
You should be able to see what's going on with the HTML and CSS... it's basic stuff. The jQuery is pretty straight forward too:
$(document).ready(function(){
// find the width of the browser window....
var docuWidth = $(window).width();
// find the width of the central column as set by the CSS...
// (you could hard code this as 980px if desired)
var centerWidth = $('#center').width();
// figure out how many pixels wide each side column should be...
sideColWidth = (docuWidth-centerWidth) / 2;
// then set the width of the side columns...
$('#left,#right').css({
width:sideColWidth+'px'
});
})
EDIT
Converted the jQuery to a function that is called when the document is ready, and again if the viewport is resized... just in case:
http://jsfiddle.net/aKeqf/