I would like to achieve a result similar to balancing text lines in print but for block elements. Say a collection of 50/50px boxes in a 300/100px container. Floating the boxes within the container will make them fill up one "row", then wrap onto the next one like this:
[1][2][3][4][5][6]
[7]
I would like them to "wrap" in a more balanced way:
[1][2][3][4]
[5][6][7]
or even better, have them "wrap" at every column filling up space as they go:
[1][3][5][7]
[2][4][6]
I figured you can do this with CSS columns but it feels like a hack because the container element need to be float:left or display:inline-block to force columns to stick together, it needs a constrained height etc. I have added a snippet for reference.
Is there a more genuine CSS way to achieve this?
.wrap {
display: inline-block; /*Needs this so make colums stick together*/
columns: 100px;
column-gap: 0;
height: 200px;
}
.wrap>div {
width: 98px;
height: 98px;
background: red;
/* styling only */
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
border: 1px solid blue;
}
<div class="wrap">
<div>1Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</div>
<div>2Mauris eu risus.</div>
<div>3Vestibulum auctor dapibus neque.</div>
<div>4Consectetuer adipiscing elit.</div>
<div>5Eu risus.</div>
<div>6Vestibulum auctor dapibus neque.</div>
<div>7Lorem ipsum dolor sit amet</div>
<div>8Aliquam tincidunt mauris eu risus. Lorem ipsum dolor sit amet, consectetur adipisicing elit.</div>
<div>9Vestibulum auctor dapibus neque.</div>
</div>
Here's a flexbox solution: Using flex-direction: column and flex-wrap: wrap on the parent element you can make the items wrap from top to bottom and fill another column once the column is filled.
This is the code to get flexbox working:
display: flex;
flex-direction: column;
flex-wrap: wrap;
align-content: flex-start;
And here's a demo:
.wrap {
background-color: silver;
height: 100px;
width: 400px;
display: flex;
flex-direction: column;
flex-wrap: wrap;
align-content: flex-start;
}
.box {
height: 50px;
width: 50px;
background-color: red;
box-sizing: border-box;
border: 1px solid white;
}
<div class="wrap">
<div class="box">1</div>
<div class="box">2</div>
<div class="box">3</div>
<div class="box">4</div>
<div class="box">5</div>
<div class="box">6</div>
<div class="box">7</div>
<div class="box">8</div>
<div class="box">9</div>
<div class="box">10</div>
</div>
Related
I'm a bit confused with how Chrome's browser/dev tools inspector is highlighting the width of a div:
In the following code, .siteFooter_upperFooterFlex__Ut3VI (yellow) visually displays as 100% width of .siteFooter_upperFooterContent__Jt8SZ (light-blue) with the inspector closed, however, when I inspect .siteFooter_upperFooterFlex__Ut3VI (yellow), I see:
Why doesn't the inspector show the yellow background color reaching the full width, which is 100%?
.siteFooter_upperFooterContent__Jt8SZ {
position: relative;
z-index: 20;
padding-top: 3rem;
padding-bottom: 3rem;
background-color: lightblue;
}
.siteFooter_upperFooterFlex__Ut3VI {
display: flex;
align-items: stretch;
justify-content: center;
background-color: yellow;
}
.siteFooter_separatorWrap___XQCE {
display: flex;
align-items: center;
justify-content: center;
}
#media (min-width: 768px) {
.siteFooter_upperFooterLeft__0MGuC {
width: 35%;
padding-left: 4rem;
padding-right: 4rem;
}
.siteFooter_upperFooterRight__FGTWq {
display: flex;
width: 35%;
flex-direction: column;
padding-left: 4rem;
padding-right: 4rem;
}
}
<div class="siteFooter_upperFooterContent__Jt8SZ">
<div class="siteFooter_upperFooterFlex__Ut3VI">
<div class="siteFooter_upperFooterLeft__0MGuC">
<div class="siteFooter_upperFooterTextWrap__Pn_No">
<p class="siteFooter_upperFooterText__ofee9">Quisque varius libero sit amet nisl blandit dictum.</p>
</div>
<div class="siteFooter_upperFooterButton__1p9RV"><a class="buttonLink_black__TlKdt"
href="/contact/sales/">Talk to Us</a></div>
</div>
<div class="siteFooter_separatorWrap___XQCE">
<div class="siteFooter_separator__NRxtG"></div>
</div>
<div class="siteFooter_upperFooterRight__FGTWq">
<div class="siteFooter_upperFooterTextWrap__Pn_No">
<p class="siteFooter_upperFooterText__ofee9">Quisque varius libero sit amet nisl blandit dictum.</p>
</div>
<div class="siteFooter_upperFooterButton__1p9RV"><a class="buttonLink_white__zKdgU"
href="https://sandbox.mandoemedia.com/sandbox-wizard">Quisque varius libero sit amet nisl blandit dictum.</a></div>
</div>
</div>
</div>
This appears to be a quirk of Chromium's dev tools implementation; I suppose it is Chromium trying to be helpful. The dev tools are showing you how much of the flex item's width is taken up by the child elements vs how much is 'padded' by the flex layout (the blueish purple boxes on the left and right edges). Note that I've specified Chromium here, not just Chrome; other Chromium browsers like Edge appear to have this "feature", too.
When you hover, note that the width amount shown (for your screenshot, that's 1157px) is more than the width of each child container added together.
The dev tools in Firefox do not make such a distinction and just show you how much space the flex item effectively takes up (which is the full width).
I'm trying to create a 3X3 image (these are image mocks of videos) gallery in a react app. I'm using sass and flexbox grid, and I'm having some trouble with css and responsiveness issues across multiple screen sizes:
here's how it looks like(as it should) on a huge iMac screen(5120 x 2880)
And on a normal sized Laptop screen, it gets messy and even the background image is breaking for some reason:
My goal is to have a responsive 3x3 grid on most common screen sizes, going down to 2x3 or 1x2 on very small screens. the size of every image must be in same ratio for all screens(if the image must resize itself to fit, so is the rest of the page).
I used create-react-app and Sass. I also have access to react-bootstrap but I haven't used any of it yet, trying to make this screen with pure flexbox. I tried wrapping every image with a wrapper div and make special rules on it but it didn't help.
Thanks for the help in advance, for the record, I'm not very experienced with advanced css, previously used basic bootstrap and helper libraries, trying to make this on my own mostly for learning purposes.
Dashboard.jsx
<div className="dashboard-page-wrapper">
<div className="page-content-wrapper">
<Gallery videosAmount = {6} videoUrl = {video}/>
</div>
</div>
Dashboard.scss
.dashboard-page-wrapper {
background-image: url("../../assets/map_bg.png");
height: 100vh;
background-size: cover;
.page-content-wrapper {
width: calc(100% - 290px);
}
}
Gallery.jsx
<div className="video-gallery-wrapper">
<ImageGallery videosAmount={videosAmount} videoUrl= {videoUrl} />
</div>
Gallery.scss
.video-gallery-wrapper {
min-height: 400px;
display: flex;
display: -webkit-flex;
flex-wrap: wrap;
flex-direction: row;
justify-content: flex-start;
align-items: auto;
align-content: center;
padding: 50px;
&:after {
display: block;
flex: 999 999 auto;
}
.image-wrapper {
img {
flex: 0 0 auto;
margin: 20px 10px 20px 20px;
height: 305px;
width: 479px;
}
}
}
Flexbox layout requires your HTML markup to have a certain structure. Because you provided prebuilt code I whipped up a comparable example that I hope helps.
The only place you need any flexbox rules is on the flex container and the flex children, that must be direct child elements of the flex container.
.wrapper {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
Here, I am applying flexbox layout to the container with display: flex. The flex-wrap rule allows the items to flow into multiple lines. And justify-content: space-between makes the items sit up against the left and right edges of the container. This provides a vertical gutter between items as long as they do not take up all the available horizontal space.
.video-item {
flex: 0 0 31%;
}
The flex child elements get this flex rule, the value is shorthand for flex-grow: 0, flex-shrink: 0, and flex-basis: 31%. The flex basis of flex items establishes a starting width, and since I have "turned off" grow and shrink the basis serves as the width from here on.
The images you put into the document will try and fight with the sizing of these divs so you need to instruct the images to obey the size of their wrapper div:
.video-wrap img {
width: 100%;
height: auto;
}
Lastly, I just change the flex-basis of the items at various screen sizes, using media queries, to control the number of items across. Check out the full example in full page mode and play with the screen size.
body {
background: #ccc;
margin: 0;
padding: 20px;
}
.wrapper {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.video-item {
flex: 0 0 31%; /* tweak the thrid value to adjust the vertical gutters */
background: #fff;
margin-bottom: 20px;
}
.video-wrap img {
width: 100%;
height: auto;
}
.text-wrap {
text-align: center;
padding: 10px;
}
#media (max-width: 640px) {
.video-item {
flex: 0 0 48%; /* 2 across */
}
}
#media (max-width: 480px) {
.video-item {
flex: 0 0 100%; /* 1 accross */
}
}
<div class="wrapper">
<div class="video-item">
<div class="video-wrap">
<img src="https://picsum.photos/270/180" />
</div>
<div class="text-wrap">
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
</div>
</div>
<div class="video-item">
<div class="video-wrap">
<img src="https://picsum.photos/270/180" />
</div>
<div class="text-wrap">
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
</div>
</div>
<div class="video-item">
<div class="video-wrap">
<img src="https://picsum.photos/270/180" />
</div>
<div class="text-wrap">
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
</div>
</div>
<div class="video-item">
<div class="video-wrap">
<img src="https://picsum.photos/270/180" />
</div>
<div class="text-wrap">
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
</div>
</div>
<div class="video-item">
<div class="video-wrap">
<img src="https://picsum.photos/270/180" />
</div>
<div class="text-wrap">
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
</div>
</div>
<div class="video-item">
<div class="video-wrap">
<img src="https://picsum.photos/270/180" />
</div>
<div class="text-wrap">
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
</div>
</div>
</div>
I've been trying - and failing - to get the following grid layout in CSS flexbox (no grid, I need to support older browsers):
As you can see, I need a
Menu bar (dark grey), always on top, always full width and fixed height
a 2x2 grid (blue and white) that's full width on portrait mode and same aspect ratio on landscape
the purple container using the rest of the available space. Stacked below on portrait and to the side on landscape.
I know about media queries, and I guess I need one to limit the .grid width, but I don't know how to get the landscape layout with that.
Looks simple enough but I guess I need your help! :(
html {
height: 100%;
}
body {
margin: 0;
padding: 0;
min-height: 100%;
display: flex;
flex-direction: column;
}
.container {
display: flex;
flex: 1 0 auto;
flex-direction: column;
}
.row {
display: flex;
flex: 1 0 auto;
flex-direction: row;
flex-wrap: wrap;
}
.col {
flex: 1 0 auto;
}
.grid {
width: 50vw;
}
.topbar {
background-color: #1f1f1f;
max-height: 50px;
}
.purple {
background-color: #663353;
}
.purple p {
padding: 2em;
}
.grid:nth-child(3n+1) {
background-color: #6798cc;
}
<div class="container">
<div class="row topbar"></div>
<div class="row wrap">
<div class="col grid"></div>
<div class="col grid"></div>
<div class="col grid"></div>
<div class="col grid"></div>
</div>
<div class="row">
<div class="col purple">
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Id ipsam rerum laborum velit obcaecati, eveniet reiciendis, veritatis ipsa ducimus recusandae quidem nesciunt dolor facilis sed neque quod.</p>
</div>
</div>
</div>
I have a div with a fixed width, which has a div with text inside. Parts of the text are in a span for coloring. The text div has all necessary styles for text-overflow with dots at the end (ellipsis), but the dots are not inheriting the span's color, because their definition is on the div. When I put the definition on the span, it ignores its parent's width.
Test code:
.container {
width: 120px;
}
.text {
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
.color {
color: #b02b7c;
}
<div class="container">
<div class="text">Lorem <span class="color">ipsum dolor sit amet, consetetur</span>
</div>
<!-- works -->
<div>Lorem <span class="text color">ipsum dolor sit amet, consetetur</span>
</div>
<!-- doesn't work -->
</div>
Is there any clean CSS way to solve this problem? I'd like to stick with text-overflow: ellipsis;, because the other solutions for text truncation are a bit messy in my opinion.
Referrent source at https://www.w3schools.com/cssref/css3_pr_text-overflow.asp
If I understand your issue correctly, this might work for you:
.container {
width:120px;
background: lightgray;
}
.text {
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
color:#b02b7c;
}
.color {
color: black;
}
<div class="container">
<div class="text"><span class="color">Lorem</span> ipsum dolor sit amet, consetetur
</div><!-- works -->
</div>
Demo Fiddle
If the ellipsis is taking the color of the div, then make the div the color you want the ellipsis to be, and use .color to set the initial text black.
Is such a thing possible using CSS and two inline-block (or whatever) DIV tags instead of using a table?
The table version is this (borders added so you can see it):
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head></head>
<body>
<table style="width:100%;">
<tr>
<td style="border:1px solid black;width:100px;height:10px;"></td>
<td style="border:1px solid black;height:10px;"></td>
</tr>
</table>
</body>
</html>
It produces a left column with a FIXED WIDTH (not a percentage width), and a right column that expands to fill THE REMAINING SPACE on the line. Sounds pretty simple, right? Furthermore, since nothing is "floated", the parent container's height properly expands to encompass the height of the content.
--BEGIN RANT--
I've seen the "clear fix" and "holy grail" implementations for multi-column layouts with fixed-width side column, and they suck and they're complicated. They reverse the order of elements, they use percentage widths, or they use floats, negative margins, and the relationship between the "left", "right", and "margin" attributes are complex. Furthermore, the layouts are sub-pixel sensitive so that adding even a single pixel of borders, padding, or margins will break the whole layout, and send entire columns wrapping to the next line. For example, rounding errors are a problem even if you try to do something simple, like put 4 elements on a line, with each one's width set to 25%.
--END RANT--
I've tried using "inline-block" and "white-space:nowrap;", but the problem is I just can't get the 2nd element to fill the remaining space on the line. Setting the width to something like "width:100%-(LeftColumWidth)px" will work in some cases, but performing a calculation in a width property is not really supported.
See: http://jsfiddle.net/qx32C/36/
.lineContainer {
overflow: hidden; /* clear the float */
border: 1px solid #000
}
.lineContainer div {
height: 20px
}
.left {
width: 100px;
float: left;
border-right: 1px solid #000
}
.right {
overflow: hidden;
background: #ccc
}
<div class="lineContainer">
<div class="left">left</div>
<div class="right">right</div>
</div>
Why did I replace margin-left: 100px with overflow: hidden on .right?
A modern solution using flexbox:
.container {
display: flex;
}
.container > div {
border: 1px solid black;
height: 10px;
}
.left {
width: 100px;
}
.right {
width: 100%;
background-color:#ddd;
}
<div class="container">
<div class="left"></div>
<div class="right"></div>
</div>
http://jsfiddle.net/m5Xz2/100/
Compatible with common modern browers (IE 8+): http://jsfiddle.net/m5Xz2/3/
.lineContainer {
display:table;
border-collapse:collapse;
width:100%;
}
.lineContainer div {
display:table-cell;
border:1px solid black;
height:10px;
}
.left {
width:100px;
}
<div class="lineContainer">
<div class="left">left</div>
<div class="right">right</div>
</div>
You can use calc (100% - 100px) on the fluid element, along with display:inline-block for both elements.
Be aware that there should not be any space between the tags, otherwise you will have to consider that space in your calc too.
.left{
display:inline-block;
width:100px;
}
.right{
display:inline-block;
width:calc(100% - 100px);
}
<div class=“left”></div><div class=“right”></div>
Quick example: http://jsfiddle.net/dw689mt4/1/
I've used flex-grow property to achieve this goal. You'll have to set display: flex for parent container, then you need to set flex-grow: 1 for the block you want to fill remaining space, or just flex: 1 as tanius mentioned in the comments.
If you can't use overflow: hidden (because you don't want overflow: hidden) or if you dislike CSS hacks/workarounds, you could use JavaScript instead. Note that it may not work as well because it's JavaScript.
var parent = document.getElementsByClassName("lineContainer")[0];
var left = document.getElementsByClassName("left")[0];
var right = document.getElementsByClassName("right")[0];
right.style.width = (parent.offsetWidth - left.offsetWidth) + "px";
window.onresize = function() {
right.style.width = (parent.offsetWidth - left.offsetWidth) + "px";
}
.lineContainer {
width: 100% border: 1px solid #000;
font-size: 0px;
/* You need to do this because inline block puts an invisible space between them and they won't fit on the same line */
}
.lineContainer div {
height: 10px;
display: inline-block;
}
.left {
width: 100px;
background: red
}
.right {
background: blue
}
<div class="lineContainer">
<div class="left"></div>
<div class="right"></div>
</div>
http://jsfiddle.net/ys2eogxm/
When you give up the inline blocks
.post-container {
border: 5px solid #333;
overflow:auto;
}
.post-thumb {
float: left;
display:block;
background:#ccc;
width:200px;
height:200px;
}
.post-content{
display:block;
overflow:hidden;
}
http://jsfiddle.net/RXrvZ/3731/
(from CSS Float: Floating an image to the left of the text)
If, like me, you want something that will expand to the end of the line even if the left-hand box wraps, then JavaScript is the only option.
I'd make use of the calc feature to get this right:
Array.from(document.querySelectorAll(".right")).forEach((el) => {
el.style.width = `calc(100% - ${el.offsetLeft + 1}px)`;
});
.container {
outline: 1px solid black;
}
.left {
outline: 1px solid red;
}
.right {
outline: 1px solid green;
}
<div class="container">
<span class="left">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin tristique aliquet quam, at commodo lorem fringilla quis.</span>
<input class="right" type="text" />
</div>
A solution using grid layout and fractional units (fr):
/* For debugging and visibility */
html, body {
border: 2px solid navy;
}
.grid-layout {
border: thick solid sandybrown;
background-color: gray;
}
.grid-layout div:nth-child(odd) {
border: 2px solid brown;
background-color: azure;
}
.grid-layout div:nth-child(even) {
border: 2px solid red;
background-color: lightyellow;
}
/* Grid layout.
* Horizontal and vertical gaps.
* two columns, fixed and responsive.
* Note no containing div per line.
*/
.grid-layout {
display: grid;
gap: 4px 2px ;
grid-template-columns: 100px 1fr;
}
<p>How to make an element fill the remainder of the line?</p>
<p>Note no encompassing div per line.</p>
<div class="grid-layout">
<div>Lorem ipsum line 1</div>
<div>Lorem ipsum dolor sit amet,
consectetur adipiscing elit,
sed do eiusmod tempor incididunt ut labore
et dolore magna aliqua.</div>
<div>Lorem ipsum line 2</div>
<div>Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris
nisi ut aliquip ex ea commodo consequat.</div>
</div>
A similar solution with encompassing divs:
.lineContainer {
display: grid;
gap: 2px 4px;
grid-template-columns: 100px 1fr;
}
<p>Display grid per line.</p>
<div class="lineContainer">
<div style="border:1px solid black; ">
Lorem ipsum …
</div>
<div style="border:1px solid black; ">
Lorem ipsum dolor sit amet,
consectetur adipiscing elit,
sed do eiusmod tempor incididunt ut labore
et dolore magna aliqua.
</div>
</div>