Why can't this flexbox be scrolled? - css

I'm trying to understand why the following code does not creates a scrollable flexbox.
var firstData = ["One", "Two", "Three", "Four"]
FillDiv();
FillDiv();
$("button").on('click', function() {
FillDiv();
});
function FillDiv() {
var newData = GetData();
for (i = 0; i < newData.length; i++) {
$(".wrapper").append('<div>Test</div>');
}
}
function GetData() {
return firstData;
}
.wrapper {
display: flex;
overflow-x: auto;
}
.wrapper div {
display: block;
width: 200px;
height: 200px;
background-color: black;
color: white;
text-align: center;
margin-left: 1%;
}
button {
margin-top: 20px;
margin-left: 10px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="wrapper">
</div>
<button>
NEXT
</button>
However, the following example does:
.container {
display: flex;
overflow-x: auto;
}
<div class="container">
<img src="https://as1.ftcdn.net/jpg/02/12/43/28/500_F_212432820_Zf6CaVMwOXFIylDOEDqNqzURaYa7CHHc.jpg" alt="">
<img src="https://as1.ftcdn.net/jpg/02/12/43/28/500_F_212432820_Zf6CaVMwOXFIylDOEDqNqzURaYa7CHHc.jpg" alt="">
<img src="https://as1.ftcdn.net/jpg/02/12/43/28/500_F_212432820_Zf6CaVMwOXFIylDOEDqNqzURaYa7CHHc.jpg" alt="">
<img src="https://as1.ftcdn.net/jpg/02/12/43/28/500_F_212432820_Zf6CaVMwOXFIylDOEDqNqzURaYa7CHHc.jpg" alt="">
<img src="https://as1.ftcdn.net/jpg/02/12/43/28/500_F_212432820_Zf6CaVMwOXFIylDOEDqNqzURaYa7CHHc.jpg" alt="">
<img src="https://as1.ftcdn.net/jpg/02/12/43/28/500_F_212432820_Zf6CaVMwOXFIylDOEDqNqzURaYa7CHHc.jpg" alt="">
</div>
Why does the scroll breaks when I add width and height in first example?

Add flex-shrink: 0 to your Test divs. Flex items are set, by default, to flex-shrink: 1, which enable them to shrink in order to prevent an overflow of the container.
For more details see "The flex-shrink factor" section in my answer here:
What are the differences between flex-basis and width?
The problem addressed above doesn't exist in your second example (with the images) because another default setting of flex items is min-width: auto. This means that flex items cannot, by default, be smaller than their content. If you override this default with img { min-width: 0 }, you'll get the same behavior as in your first example.
For more details about the flex minimum sizing algorithm see:
Why don't flex items shrink past content size?

Related

How to arrange intersected sections with variable heights [duplicate]

This question already has answers here:
CSS-only masonry layout
(4 answers)
Closed 11 months ago.
I have a report that has to be in blocks (divs), these divs must be aligned horizontally (with width of 50% for each), meaning that the second is to right of the first, and the third must be below the first one regardless of the height of the second.
My description might be a little fuzzy, so I attached an image that represents the idea:
Sample:
Thank you very much in advance.
I tried normal CSS hacks (float, position, display) and so on; and it didn't work.
I tried grid layout, and I tried to use Bootstrap properties; in all the above, block number 3 starts, yes, below block one but after the end of block number 2 height.
Try this:
.maindiv { /* Masonry container */
column-count: 2;
column-gap: 1em;
}
.item { /* Masonry bricks or child elements */
display: inline-block;
margin: 0 0 1em;
width: 100%;
}
here's a quick way of doing it with flexbox, link to codepen. The downside is that you would need to have 2 columns, so on mobile, the second col would go below the first one. Ideally, you would do this with CSS Grid, or JS Masonry plugin
And here's the code itself:
HTML:
<div class="example-wrap">
<div class="col">
<div class="card" style="height: 100px;"></div>
<div class="card"></div>
<div class="card" style="height: 400px;"></div>
</div>
<div class="col">
<div class="card"></div>
<div class="card" style="height: 400px;"></div>
<div class="card" style="height: 150px;"></div>
</div>
CSS:
.example-wrap {
display: flex;
width: 600px;
justify-content: space-between;
align-items: flex-start;
box-shadow: 0 0 0 1px black;
}
.col {
width: calc((100% - 30px) / 2);
}
.card {
width: 100%;
height: 300px;
box-shadow: 0 0 0 1px red;
margin-bottom: 30px;
}
Masonry is the best way to do what you want.
var elem = document.querySelector('.grid');
var msnry = new Masonry( elem, {
// options
itemSelector: '.grid-item',
columnWidth: 200
});
// element argument can be a selector string
// for an individual element
var msnry = new Masonry( '.grid', {
// options
});
.grid-item {
width: 40%;
margin: 20px;
border: 1px solid black;
height: 100px;
text-align: center;
color: red;
font-weight:700;
}
.height-2 {
height:300px;
}
<script src="https://unpkg.com/masonry-layout#4.2.2/dist/masonry.pkgd.min.js"></script>
<div class="grid">
<div class="grid-item">1</div>
<div class="grid-item height-2">2</div>
<div class="grid-item height-2">3</div>
<div class="grid-item">4</div>
</div>
See Masonry for more options/methods : https://masonry.desandro.com/

Make an element take up available horizontal space without causing its parent to widen

I have a flexbox container with exactly two children, both of which can have variable content. I want the width of the entire container to fit the width of the first child, but I want the second child's contents to wrap and not cause the container to grow horizontally. See the runnable snippet below for a visual problem description.
Currently looking for a CSS Grid solution. I have found one partial solution, but relies on JavaScript: Make the second child a relative container, put its contents in an intermediate absolutely-positioned container, and use JS to set a fixed height. At least it's good for showing what I'm looking for.
Problem:
.container {
display: inline-flex;
flex-direction: column;
border: 1px solid red;
}
.child {
background-color: wheat;
margin: 5px;
}
<div class="container">
<div class="first child">
This content can grow and be as wide as it wants
</div>
<div class="second child">
This content will also be any size it wants, but I * want it to wrap at the asterisk in this sentence, which is where the first child above would naturally end. This will be its own flexbox container holding several buttons that should wrap onto new rows.
</div>
</div>
JavaScript/absolute solution:
let second = document.getElementsByClassName('second')[0]
let content = document.getElementsByClassName('absolute')[0]
second.style.height = content.offsetHeight + 'px'
.container {
display: inline-flex;
flex-direction: column;
border: 1px solid red;
}
.child {
background-color: wheat;
margin: 5px;
}
.second {
position: relative;
/* height to be set by JS */
}
.absolute {
position: absolute;
width: 100%;
top: 0;
left: 0;
}
<div class="container">
<div class="first child">
This content can grow and be as wide as it wants
</div>
<div class="second child">
<div class="absolute">
This content is longer than the above but still wraps in the right place.
</div>
</div>
</div>
Just set min-width and width of .second:
.container {
border: 1px solid red;
display: inline-block;
padding: 5px;
}
.child {
background-color: wheat;
}
.second {
margin-top: 10px;
min-width: 100%;
width: 0;
}
<div class="container">
<div class="first child">
This content can grow and be as wide as it wants
</div>
<div class="second child">
This content will also be any size it wants, but I * want it to wrap at the asterisk in this sentence, which is where the first child above would naturally end. This will be its own flexbox container holding several buttons that should wrap onto new rows.
</div>
</div>

Html element with height set to 100vh does not always span the whole page height

I've got this strange issue with my body content container. I want it to be as tall as the view port so I set its height to 100vh in the css. It works in all pages except for the one where I try to make a bootstrap grid inside this body content container.
Here you can see how it looks:
The blue-ish div is my body content.
When I zoom all the way out, they blue div's height is indeed 100vh.
Inside of it I've got this
<div class="container body-content">
<div class="row text-center">
#foreach (var item in Model.Products)
{
#Html.Partial("ProductColumn", item)
}
</div>
</div>
where Html.Partial renders on every iteration something like this:
<div class="col-lg-3 col-md-3 col-sm-4 col-xs-12 product-column-wrapper">
<div class="product-column">
//product title
<div id="thumbnail-container">
<a class="d-block mb-4 h-100" asp-route="#WebConstants.Routes.ProductDetails" asp-route-id="#Model.Id" asp-route-title="#Model.Name">
<img id="thumbnail" src="#Model.ThumbnailSource" class="img-responsive img-thumbnail" alt="#Model.Name">
</a>
</div>
//price
//Edit, Delete buttons
</div>
</div>
Here is some of my css classes:
body {
padding-top: 50px;
padding-bottom: 20px;
}
footer {
color: white;
font-size: 13px;
text-align: center;
vertical-align: middle;
max-height: 15px;
}
.body-content {
background: aliceblue;
border-radius: 5px;
padding: 10px;
height: 100vh;
}
If anyone could help me find out how to stretch the body content in this scenario, that would be great.
Instead of height: 100vh try using min-height: 100vh. E.g.
.body-content {
background: aliceblue;
border-radius: 5px;
padding: 10px;
min-height: 100vh;
}

How to Center Masonry Container

I'm trying to center a masonry container on a page. At the moment, it's aligned to the left. I have margin auto in my CSS and isFitWidth: true in JS, but neither seems to be doing anything. I've also tried putting display:block in my CSS.
This is the HTML;
<div id="masonry_container" class="group">
<div class="masonry_item">
<a href="http://storyville.jonmarkoff.com/storyvillewp"target="_blank">
<img src="images/storyville_home.png" alt="Storyville Entertainment"/>
<h3>Storyville Entertainment</h3></a>
</div><!--masonry_item-->
<div class="masonry_item">
<a href="http://www.ducklingfarm.com"target="_blank">
<img src="images/udof_home.jpg" alt="Ugly Duckling Organic Farm"/>
<h3>Ugly Duckling Organic Farm</h3></a>
</div> <!--masonry_item-->
<div class="masonry_item">
<a href="http://www.underdonk.com"target="_blank">
<img src="images/underdonk_home.png" alt="underdonk"/>
<h3>Underdonk</h3></a>
</div> <!--masonry_item-->
<div class="masonry_item">
<a href="http://www.jaeeunlee.com" target="_blank">
<img src="images/jaeeunlee_home.png" alt="jaeeunlee"/>
<h3>www.jaeeunlee.com</h3></a>
</div> <!--masonry_item-->
<div class="masonry_item">
<img src="images/goindoor_hospitals.png" alt="goindoor"/>
<h3>Goindoor</h3>
</div> <!--masonry_item-->
<div class="masonry_item">
<img src="images/cakes_home.jpg" alt="wonderfully whimsical cakes"/>
<h3>Wonderfully Whimsical Cakes</h3>
</div> <!--masonry_item-->
</div><!--#masonry_container .group-->
CSS;
.group {
display: inline-block;
clear:both;
}
.group:after {
visibility: hidden;
display: block;
font-size: 0;
content: " ";
clear: both;
height: 0;
}
#masonry_container {
margin:50px auto;
width:100%;
position:relative;
z-index:2001;
}
.masonry_item {
width:300px;
margin:0 0 20px 0px;
padding:20px;
}
.masonry_item:hover{
outline:1px solid white;
}
#masonry_container img {
width:100%;
}
and JS;
var container = document.querySelector('#masonry_container');
var msnry = new Masonry( container, {
// options
isFitWidth: true,
itemSelector: '.masonry_item'
});
I'd appreciate your help!
I was trying to figure this out for myself today and thought I'd share a possible solution.
As per Masonry's own options page "isFitWidth": true seems to be the key
http://masonry.desandro.com/options.html#isfitwidth
Here's their codepen example..
http://codepen.io/desandro/pen/nGLvx
Here's my simplified and bare bones method..
fiddle
https://jsfiddle.net/Hastig/xtw113wx/2/ - code play
https://jsfiddle.net/Hastig/xtw113wx/2/embedded/result/ - full screen
html
<div class="masonry-container js-masonry" data-masonry-options='{ "isFitWidth": true }'>
<div class="image-div">
<img class="image" src="" style="width: 200px; height: 100px;">
</div>
<!-- ..lots more divs in jsfiddle.. -->
</div>
css
.masonry-container {
margin: 0 auto; /* this is the css that keeps the container centered in page */
}
.image-div {
float: left;
width: 230px;
margin: 5px;
font-size: 0;
}
.image {
width: 230px;
height: auto;
}
Try this in the css:
.masonry_item {
width:300px;
margin:0 auto 20px auto;
padding:20px;
}
EDIT
I didn't read this correctly the first time. If you want to center the actual container you will need to set a fixed size for the container instead of 100%. Maybe 500px. Then remove the display: inline-block from the .group class. That should do it.
Set a fixed size for the container, such as width = 300px; height = 500px. Then, move the container with left: 50%; top: 50%. Finally, set the margin-left to -1/2 the value of the width, and margin-top to -1/2 the value of the height. This only works with absolute positioning.

Vertical aligning an absolute positioned div inside a containing div

I'm using the jQuery Cycle plugin to rotate images in a slideshow type fashion. That works fine. The problem I'm having is getting these images (of different sizes) to center in the containing div. The images are inside a slidshow div that has it's position set to absolute by the Cycle plugin.
I've tried setting line-height/vertical-align and whatnot but no dice. Here is the relevant HTML and CSS
HTML:
<div id="projects">
<div class="gallery">
<span class="span1">◄</span><span class="span2">►</span>
<div class="slideshow">
<img src="images/img1.png" />
<img src="images/img1.png" />
<img src="images/img1.png" />
</div>
</div>
</div>
CSS:
#main #home-column-2 #projects
{
width: 330px;
background: #fefff5;
height: 405px;
padding: 12px;
}
#main #home-column-2 #projects .gallery
{
width: 328px;
height: 363px;
position: relative;
background: url('images/bg-home-gallery.jpg');
}
#main #home-column-2 #projects .gallery img
{
position: relative;
z-index: 10;
}
And in case you want to see it, the jQuery:
$('#home-column-2 #projects .gallery .slideshow').cycle(
{
fx: 'scrollHorz',
timeout: 0,
next: "#home-column-2 #projects .gallery span.span2",
prev: "#home-column-2 #projects .gallery span.span1"
});
Any ideas on getting these images to center?
Try this:
http://www.brunildo.org/test/img_center.html
Vertical centering is a pain! Here's what the W3C page says about the vertical center:
CSS level 2 doesn't have a property
for centering things vertically. There
will probably be one in CSS level 3.
But even in CSS2 you can center blocks
vertically, by combining a few
properties. The trick is to specify
that the outer block is to be
formatted as a table cell, because the
contents of a table cell can be
centered vertically.
This method involves a little jquery, but works fantastic in most situations...
let me explain:
if all the images of the slideshow are contained within their own element div pos:absolute and those images are pos:relative, then on a $(window).load() you can run a .each() and find each img in the slideshow and adjust it's top positioning to be offset a certain number of pixels from the top..
jcycle automatically sets each parent div containing the image to pos:absolute on every onafter() so it's useless to apply this pos adjustment to them... instead target each img you have set to pos:relative...
Here is the example:
$(window).load(function() {
// move all slides to the middle of the slideshow stage
var slideshowHeight = 600; //this can dynamic or hard-coded
$('.slideImg').each(function(index) {
var thisHeight = $(this).innerHeight();
var vertAdj = ((slideshowHeight - thisHeight) / 2);
$(this).css('top', vertAdj);
});
});
and this is the html it's working on...
<div class="slideshow" style="position: relative; ">
<div style="position: absolute; top: 0px; left: 0px; display: none; width: 1000px; height: 600px; " id="img0">
<img class="slideImg" src="/images/picture-1.jpg" style="top: 0px; "><!-- the style=top:0 is a result of the jquery -->
</div>
<div style="position: absolute; top: 0px; left: 0px; display: none; width: 1000px; height: 600px; " id="img1">
<img class="slideImg" src="/images/picture-1.jpg" style="top: 89.5px; "><!-- the style=top:89.5px is a result of the jquery -->
</div>
<div style="position: absolute; top: 0px; left: 0px; display: none; width: 1000px; height: 600px; " id="img2">
<img class="slideImg" src="/images/picture-1.jpg" style="top: 13px; "><!-- the style=top:13px is a result of the jquery -->
</div>
</div>
just make sure
.slideImg {
position:relative;
}
I think that's everything... I have an example, but it's on a dev site.. so this link might not last.. but you can take a look at it here:
http://beta.gluemgmt.com/portfolio/rae-scarton-editorial.html
The positions are relative according to the style sheet, so did you try setting them to display: block and margin-top: auto; margin-bottom: auto; ?
Another option is to align them manually in javascript based on the containing div's height.
You need to nest two divs inside each cycle item. The first must have the display: inline-table; and the second must have display: table-cell; both these divs have vertical-align: middle.
So the structure would look something like this:
<div class="slide-container">
<div class="slide">
<div class="outer-container">
<div class="inner-container">
Centered content
</div>
</div>
</div>
<div class="slide">
<div class="outer-container">
<div class="inner-container">
Centered content
</div>
</div>
</div>
</div>
With the following css:
.slide-container {
height: 300px;
}
.outer-container {
height: 300px;
display: inline-table;
vertical-align: middle;
}
.inner-container{
vertical-align: middle;
display: table-cell;
}
You can see it working here http://jsfiddle.net/alsweeet/H9ZSf/6/

Resources