Trying to create a responsive image gallery, react+Sass+Flexbox - css

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>

Related

Issue with responsive media queries using pure css

So here is the link to my project repository
https://github.com/iamlovingawareness/EdgeLedger/tree/main
In the following code snippet I am not able to implement this change:
in the solutions and cases section when the max-width is 768px it should stack one on top of the other but when I make the necessary changes in my styles.css file it shows as an error.
This is what I implemented as follows:
#media (max-width: 768px) {
.navbar {
flex-direction: column;
height: 120px;
padding: 20px;
}
.navbar a {
padding: 10px 10px;
margin: 0 3px;
}
.flex-items {
flex-direction: column;
}
.flex-columns .column,
.flex-grid .column {
flex-direction: column;
flex: 100%;
max-width: 100%;
}
.team img {
width: 70%;
}
}
Supporting HTML snippet
<section class="solutions flex-columns">
<div class="row">
<div class="column">
<div class="column-1">
<img src="./image_resources/home/people.jpg" alt="" />
</div>
</div>
<div class="column">
<div class="column-2 bg-primary">
<h4>What you are loooking for</h4>
<h2>We provide bespoke solutions</h2>
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Est,
aut!
</p>
<a href="#" class="btn btn-outline"
><i class="fas fa-chevron-right"></i> Read More</a
>
</div>
</div>
</div>
</section>
Where .flex-columns . columns is what is supposed to do the thing but is not.
Kindly help me out thank you
Update: Went to chrome dev tools to see what was going on and saw this in the element property section:
Here as you can see there is a slash on the property that is supposed to be acting when the max-width is 768px. My question now is how do I find out where it has been overridden and make the necessary changes.
Thanks !

Align text left above (relative to) div

I have some h2 text that is currently aligned to the left in the mobile view, above a centered div. How can I instead align it flush left relative to the div in the mobile view (with media query provided in the CSS below applied)?
CodePen
Relevant HTML:
<section class="container-projects">
<h2 class="portfolio-header">Featured Work</h2>
<div class="project">
Relevant CSS:
.portfolio-header {
/* Puts header in its own row without removing from container with row flex direction (setting parent container to wrap also required) */
width: 100%;
text-align: left;
color: #7d97ad;
}
.container-projects {
display: flex;
/* Parent container needs this for flex-item to take full width in row */
flex-wrap: wrap;
flex-direction: row;
justify-content: space-between;
margin: 2em 0;
}
/* Special styling for screens up to 767px wide, inclusive (applies to landscape phones) */
#media screen and (max-width: 767px) {
header, .container, footer {
max-width: 100%;
}
/* Must specify max-width for img even though parent .container has the same declaration because max-width isn't inherited */
.container img {
max-width: 100%;
}
.project {
/* Centers projects (aligned left otherwise) */
margin: 0 auto;
}
}
https://codepen.io/anon/pen/OZjWwJ?editors=1100
Slightly modified HTML
<section class="portfolio">
<h2 class="portfolio-header">Featured Work</h2>
<div class="container-projects">
<div class="project">
<img class="project-image" src="https://image.ibb.co/hv4c8n/santorini_small.jpg" alt="View from island of Santorini on a sunny day">
<h3>Project No. 1</h3>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
</div>
<div class="project">
<img class="project-image" src="https://image.ibb.co/c9sKM7/coast_small.jpg" alt="Distant view of a rugged island with a sailboat nearby">
<h3>Project No. 2</h3>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
</div>
<div class="project">
<img class="project-image" src="https://image.ibb.co/eO9oES/mediterranean_small.jpg" alt="Bird's eye view of a rocky beach with clear turquoise waters">
<h3>Project No. 3</h3>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
</div>
</div>
</section>
and CSS
.portfolio {
margin: 0 auto;
width: 100%;
}
#media screen and (max-width: 992px) {
.portfolio {
width: 90%;
}
}
This way, you are wrapping both your h2 and your project images in one container, which makes it a little more logical to manage their margin on screen. margin: 0 auto aligns the container at the center of the screen, which is desirable on all screen widths.
The 992px media query comes from Bootstrap 4's standardized grid system: https://getbootstrap.com/docs/4.0/layout/grid/#grid-options
You can add media query for mobile
#media screen and (max-width: 600px) {
.portfolio-header {
width: 300px;
margin: 10px auto;
}
}

Balancing block elements like lines of text in print

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>

How do I get a lone element in the last line of a flexbox layout to look the same?

I'm trying to create some CSS for a list of rectangles, with wrapping, that is responsive. The rectangles can contain a variable amount of text. The rectangles should have a minimum width of 300px, but can grow if there is more space available. It should work no matter the number of rectangles.
This is an image of what I want it to look like, in a wide desktop screen, a normal desktop screen and a phone, roughly:
(I realise that most phone and desktops are wider than that in pixels, but these numbers are easier to work with when it comes to SO's code snippets.)
I'm trying three techniques, and none of them do what I want:
1. Flexbox doesn't work:
Flexbox would seem ideal for this job. The trouble with the flexbox implementation is that I can't find a way to make sure the last rectangle stays the same size as the rest, while also allowing the rectangles to grow in very wide screens. Here's an image of the best flexbox result that I could come up with, which has the problem with the last line:
Here's the code of the flexbox implementation:
.container {
display: flex;
flex-wrap: wrap;
}
.rect {
flex: 1 0 300px;
height: 150px;
}
<div class="container">
<div class="rect" style="background-color: #2F80ED"></div>
<div class="rect" style="background-color: #2D9CDB"></div>
<div class="rect" style="background-color: #56CCF2"></div>
<div class="rect" style="background-color: #A6E2F5"></div>
<div class="rect" style="background-color: #D6EBF2"></div>
</div>
2. float: left technique doesn't work:
Another responsive technique is to use floats, but I can't find a way to keep the rectangles the same width (with varying text content), while also allowing them to grow in the widest screens. Here's an image of what I ended up with:
Here's the code of the float: left implementation:
.container:after {
content: "";
clear: both;
}
.rect {
float: left;
min-width: 300px;
height: 150px;
overflow-y: hidden;
}
<div class="container">
<div class="rect" style="background-color: #2F80ED">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod</div>
<div class="rect" style="background-color: #2D9CDB"></div>
<div class="rect" style="background-color: #56CCF2">Lorem ipsum dolor sit amet, consectetur</div>
<div class="rect" style="background-color: #A6E2F5">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed</div>
<div class="rect" style="background-color: #D6EBF2"></div>
</div>
3. Why not media queries?
I'm looking for a solution that doesn't involve media queries, as media queries only let you put conditions on the screen width, and not on the .container width.
You may keep using flex with an extra element via a pseudo with no height:
.container {
display: flex;
flex-wrap: wrap;
background:gray;/*see me */
}
.container:after {
content:'';
flex: 1 0 300px;
margin-bottom:auto;
}
.rect {
flex: 1 0 300px;
height: 150px;
}
<div class="container">
<div class="rect" style="background-color: #2F80ED"></div>
<div class="rect" style="background-color: #2D9CDB"></div>
<div class="rect" style="background-color: #56CCF2"></div>
<div class="rect" style="background-color: #A6E2F5"></div>
<div class="rect" style="background-color: #D6EBF2"></div>
</div>
:Note that is fine for five, for six boxes behavior is different.
I know you said that you were looking for an answer that didn't involve media-queries, but I believe it would be the best way to handle this situation.
If you set position: relative; on your .container all of it's children will base their width percentage off of .container's width. While technically you would still be basing your conditions off of the screen width you can still set the container width to any size you want and the .rect's will scale to that width, it would just depend on which of your media queries were active for what percentage your .rect's would be scaling to.
You could also set a max-width: for your .container in any of those media queries if you don't want it to grow past a certain size.
Here is a link to a pen which has the layout looking like your intended images above. http://codepen.io/bryanrunner/pen/BppzbE
.container {
position: relative;
display: flex;
flex-flow: row wrap;
max-width: 1200px;
}
.rect {
height: 150px;
}
#media (max-width: 1920px) {
.rect {
width: 20%;
}
}
#media (max-width: 1000px) {
.rect {
width: 50%;
}
}
#media (max-width: 600px) {
.rect {
width: 100%;
}
}

How to display HTML content in columns, horizontally scrollable?

I have a list of simple HTML elements like divs, Paragraphs, etc. I'd like to display them in fixed height container, with the content shown in columns with same fixed width, all horizontally scrollable, just like it's shown on this picture.
The browser it should work in is IE11.
Any idea, how to implement it? Thanks.
Put them all in:
<div class="sample"></div> and wrap them in a <div class="container"></div>
Give all .sample classes and .container a fixed width and height.
.sample {
width: 900px;
height: 500px;
}
.container {
overflow-x: scroll;
overflow-y: hidden;
}
You could use css3 columns
http://www.w3schools.com/cssref/css3_pr_columns.asp
<div id="main">
Content here, no wrapping divs needed...
</div>
Or even better using html5
<main>
Content here, no wrapping divs needed...
</main>
You must put all the elements in a container, and give it a width large enough to not wrap the elements around. The elements should either float: left or display: inline-block.
Then put a div pane around, which shows a cutout of the container and give that pane overflow-x: auto in order to show a scrollbar when necessary
<div class="pane">
<div class="container">
<p class="column">Lorem ipsum dolor sit amet, ...</p>
<div class="column">Lorem ipsum dolor sit amet, ...</div>
<div class="column">Lorem ipsum dolor sit amet, ...</div>
<p class="column">Lorem ipsum dolor sit amet, ...</p>
</div>
</div>
.pane {
width: 100%;
height: 380px;
overflow-x: auto;
}
.container {
width: 1250px;
max-height: 350px;
}
.container .column {
display: inline-block;
width: 300px;
}
See JSFiddle

Resources