I have a flex box which has flex items in it, each having a certain order.
I want to set it so that when the flex box (not the screen, etc.) gets smaller than 500px the order changes (and maybe also one of the margins).
Here's the code:
HTML
<div class="flex-box">
<div class="flex-item-0"></div>
<div class="flex-item-0"></div>
<div class="flex-item-0"></div>
<div class="flex-item-2"></div>
<div class="flex-item-2"></div>
<div class="flex-item-3"></div>
</div>
CSS
.flex-box{
display: flex;
flex-flow: row wrap;
align-items: center;
justify-content: center;
}
.flex-item-0{
order: 0;
}
.flex-item-2{
order: 2;
}
.flex-item-3{
order: 3;
margin-left: auto;
}
and when the flex-box gets less than 500px (or whatever specified amount) I want flex-item-3 to change to:
.flex-item-3{
order: 1;
/*margin-left: auto;*/
}
(I comment out the margin-left: auto; so the it is noted that is has been taken out)
I know there are #media queries however I am not sure how they would apply in this situation.
Does anyone know how to change a CSS style whenever the containing box gets less than a specific width? (CSS solution preferred but fine with JS/jQuery)
With CSS, as you said, you can use media queries.
In this case you would use:
#media (max-width:500px) {
.flex-item-3 {
order: 1;
margin-left: initial;
}
}
CODE SNIPPET:
.flex-box {
display: flex;
flex-flow: row wrap;
align-items: center;
justify-content: center;
/*---Demo---*/
margin-top: 40px;
border: 1px solid #262626;
/*---Demo---*/
}
.flex-item-0 {
order: 0;
}
.flex-item-2 {
order: 2;
}
.flex-item-3 {
order: 3;
margin-left: auto;
/*---Demo---*/
font-weight: bold;
background-color: tomato;
/*---Demo---*/
}
#media (max-width: 500px) {
.flex-item-3 {
order: 1;
margin-left: initial;
}
}
<div class="flex-box">
<div class="flex-item-0">0</div>
<div class="flex-item-0">0</div>
<div class="flex-item-0">0</div>
<div class="flex-item-2">2</div>
<div class="flex-item-2">2</div>
<div class="flex-item-3">3</div>
</div>
Related
I am developing a website, in which I display N amount of images. A good example of how I would like to display them is how DeviantArt does it. Images are shown in rows in such a way that it fills the width of the current viewport and does not deform any images.
My attempt was the following:
#CSS
.item {
display: inline-block;
vertical-align: top;
position: relative;
overflow: hidden;
padding: 0.5em;
background: lightcoral;
border: black solid 1px;
}
.item img{
max-height: 200px;
object-fit: scale-down;
}
HTML
<div style="display: block; width: 100%">
<!-- A vue directive, used in this example to render this element n amount of times per images -->
<div class="item" v-for="(i, index) in images" :key="index">
<img :src="i.url">
<div style="display: flex; flex-direction: column;">
<div>{{i.title}}</div>
<div>By User1234</div>
</div>
</div>
</div>
Which results in the following:
As you can see, there are gaps left at the end of each row. Id like for each row to be able to fit all possible images so that the grid fits the viewport, like this:
Im very interested to know how I can achieve this, either by using pure HTML / CSS or Javascript if needed.
You probably want to use flexbox with flex-grow.
CSS-Tricks has a great article on this here: https://css-tricks.com/piecing-together-approaches-for-a-css-masonry-layout/
Here's a codepen from the article:
codepen
body {
margin: 0;
padding: 1rem;
}
.masonry-with-columns {
display: flex;
flex-wrap: wrap;
div {
height: 150px;
line-height: 150px;
background: #EC985A;
color: white;
margin: 0 1rem 1rem 0;
text-align: center;
font-family: system-ui;
font-weight: 900;
font-size: 2rem;
flex: 1 0 auto;
}
#for $i from 1 through 36 {
div:nth-child(#{$i}) {
$h: (random(400) + 70) + px;
width: $h;
}
}
}
At the moment I'm using flex with justify-content: center; and padding left on B component. Is a temporary hack. How can I do it to work properly?
When the container is big, I want them centred but with a space in the middle. When is small, I would like to have them to go on top of each other.
Note:
On the large screen the 2 items are centred and have a gap between.
Should not be based on the screen size because the wrapper can be small on a desktop for example.
No JS solution like component media query;
One of the solutions could be something like this: https://www.npmjs.com/package/react-element-query but uses JS.
Media query doesn't work because https://jsfiddle.net/t4j6z7og/
Why not simply make use of a media query to swap to flex-direction: column at the smaller width, and swap the margin for B from margin-left to margin-top?
This can be seen in the following example
(hit 'Run code snippet' then 'Full page' for the side-by-side view):
.container {
display: flex;
justify-content: center;
align-items: center;
}
.a, .b {
width: 300px;
height: 100px;
border: 1px solid black;
}
.b {
margin-left: 20px;
}
#media screen and (max-width: 768px) {
.container {
flex-direction: column;
}
.b {
margin-left: 0;
margin-top: 20px;
}
}
<div class="container">
<div class="a">A</div>
<div class="b">B</div>
</div>
Hope this helps! :)
I currently have this design piece to create. I initially built it using 3 separate square div containers with independent background images just clipped out of the design, but this feels a big rigid to me (we would need to chop up and re-stage a new image each time we want to change it) as well as bulky. Ideally, I'd like to use one single image across each element container so that it can be easily updated. This also saves on two unnecessary server requests, which I'm in favor of!
Just wanted to poll to see if there's a better / more dynamic way to accomplish this. Thinking perhaps with javascript? Any help or points in the right direction would be greatly appreciated. Below is an outline of how I currently have it built. Attached is snippet of the design mockup for reference.
HMTL
<div class="grid-container">
<div class="grid-1 gi" style="background-image:url(image1.jpg);">Facebook</div>
<div class="grid-2 gi" style="background-image:url(image2.jpg);">Twitter</div>
<div class="grid-3 gi" style="background-image:url(image3.jpg);">Instagram</div>
</div>
CSS
.gi {
background-position: center center;
background-size: cover;
width: 32.333%;
}
.grid-1 {
margin-right: 1%;
}
.grid-2 {
margin: 0 1%;
}
.grid-3 {
margin-left: 1%;
}
So, I'm dumb and found a simple and elegant workaround! Rather than clipping, I just created two pseudo borders to server as dividers inside a wrapper with the desired background image and gave each the proper background color. Solution & jsfiddle below.
HTML
<div class="social-blocks flex" style="background-image: url(http://localhost:8888/sts-store/wp-content/uploads/2016/01/eric.jpg)">
<div class="social-block auto-ar oneone flex align-center-center block-1" style="height: 381px;">
<div>facebook</div>
</div>
<div class="pseudo-margin"></div>
<div class="social-block auto-ar oneone flex align-center-center block-2" style="height: 381px;">
<div>twitter</div>
</div>
<div class="pseudo-margin"></div>
<div class="social-block auto-ar oneone flex align-center-center block-3" style="height: 381px;">
<div>instagram</div>
</div>
</div>
CSS
.align-center-center {
align-items: center;
-webkit-align-items: center;
-moz-align-items: center;
-ms-align-items: center;
justify-content: center;
-ms-justify-content: center;
-moz-justify-content: center;
-o-justifty-content: center;
}
.flex {
display: flex;
display: -webkit-flex;
display: -moz-flex;
display: -ms-flex;
display: -o-flex;
}
.social-block {
width: 32.333%;
overflow: hidden;
position: relative;
color: #fff;
text-transform: uppercase;
font-weight: 600;
font-size: 28px;
font-style: italic;
}
.social-blocks {
margin-bottom: 2%;
background-position: center bottom;
background-size: cover;
}
.social-blocks-bg {
width: 100%;
}
.pseudo-margin {
width: 2%;
background-color: rgb(247,247,247);
}
https://jsfiddle.net/942g38qv/8/
Is it possible to transition the items in an flexbox?
When you click I want all items to collapse except the one that is clicked.
The one that is clicked should use all available space from the container.
// only works once!
$(".item").click(function() {
$(".item").not(this).each(function() {
$(this).addClass("collapse");
});
});
html, body {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
border: 0;
overflow: hidden;
}
.container {
flex-grow: 1;
flex-shrink: 0;
flex-basis: auto;
display: flex;
flex-direction: column;
height: 100%;
}
.item {
flex-grow: 1;
flex-shrink: 1;
flex-basis: auto;
transition: all 2s;
}
.collapse {
flex-grow: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
<div class="item" style="background: red">a</div>
<div class="item" style="background: green">b</div>
<div class="item" style="background: blue">c</div>
<div class="item" style="background: purple">d</div>
</div>
JSFiddle: http://jsfiddle.net/clankill3r/L8hktsgn/
flex-grow is animatable but only if the value is a <number>. However it seems that Google Chrome (v41) doesn't trigger the animation if the value is set to 0.
A workaround for this could be to use a very small value instead — something like 0.0001:
Updated example.
$(".item").click(function() {
$(".item").addClass("collapse");
$(this).removeClass("collapse");
});
html, body {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
border: 0;
overflow: hidden;
}
.container {
flex-basis: auto;
display: flex;
flex-direction: column;
height: 100%;
}
.item {
flex-grow: 1;
flex-shrink: 1;
flex-basis: auto;
transition: all 2s;
}
.collapse {
flex-grow: 0.001;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
<div class="item" style="background: red">a</div>
<div class="item" style="background: green">b</div>
<div class="item" style="background: blue">c</div>
<div class="item" style="background: purple">d</div>
</div>
$(".item").click(function() {
$(this).removeClass('collapse');
$(".item").not(this).each(function() {
$(this).addClass("collapse");
});
});
and you can animate flex-grow from 20 to 1
.item {
flex-grow: 20;
transition: all 1s;
}
.collapse {
flex-grow: 1;
}
http://jsfiddle.net/L8hktsgn/11/
If you want only one row this could work https://codepen.io/balvin/pen/gKrXdM but if you want to wrap them you could use https://codepen.io/balvin/pen/wXGyYw
Seems that it's a hack, but setting width:0;flex-grow:1 it's the solution, but in order to wrap the elements, you need to explicity tell width to the browser, because it does not know at which width you want the elemements to wrap, and with that in mind you just play with setTimeout. Check the codes
You can work with max-height.
.item
{
max-height:100%;
}
.collapse
{
max-height: 64px;
}
http://jsfiddle.net/L8hktsgn/9/
I'm making a simple IDE for a educational programming language similar to Karel the Dog. And I have trouble with making base html page.
I have 4 areas:
Toolbox (for buttons like open, save as, run etc.)
Field (canvas for drawing executor that can move on the field and do some stuff)
Code (CodeMirror editor for writing executor's commands)
Console (place where IDE can print messages like compilation errors or runtime debug output)
I wrote what I want from every area in my code so I'll say only what is not working now:
The page should fill 100% screen's height.
Cannot set CodeMirror to fill all available to its parent height. And when its size is greater than parent's height, scrollbars should appear.
The same problem with canvas - but only on vertical.
Is there a way to make a separator between code and field areas that can be used to redistribute horizontal space between areas?
There is another difficulty. If the item number 4 requires JavaScript, then I'll ask to help me with solving it with WinJS 3.0 library because I won't add to the project jQuery or other heavy stuff only for this resize capability.
So, can anyone help me?
I loaded my code to jsfiddle.net and pasted it here:
var ce = CodeMirror(document.getElementById('b-codemirror'), {
value: "\n\n\nIt is CodeMirror element. [PARAMS ALL] " +
"width: 100% of parent element, height: always 100% of" +
" parent element + both scrollbars if needed\n\n\n",
lineNumbers: true
});
var cc = document.getElementById("canvas").getContext("2d");
cc.font = "16px Helvetica";
cc.fillText("It is canvas. Can be resized from", 10, 30);
cc.fillText("JS. If it is larger than parent element,", 10, 60);
cc.fillText("corresponding scrollbar should appear.", 10, 90);
#import url("http://codemirror.net/lib/codemirror.css");
/* overriding default codemirror.css */
.CodeMirror {
font-family: monospace;
height: 100%;
}
html, body {
height: 100%;
margin: 0;
padding: 0;
}
.b-section {
margin: 2px;
padding: 4px;
border-radius: 4px;
}
#b-fieldcode {
min-height: 640px;
display: -webkit-flex;
display: flex;
-webkit-flex-flow: row;
flex-flow: row;
}
#b-toolbox {
background: #ffeebb;
}
#b-console {
height: 100px;
background: #ffeebb;
}
#b-field {
background: #ccccff;
overflow: auto;
-webkit-flex: 1 1 40%;
flex: 1 1 40%;
-webkit-order: 1;
order: 1;
}
#b-code {
background: #dddd88;
-webkit-flex: 1 1 60%;
flex: 1 1 60%;
-webkit-order: 2;
order: 2;
}
#media all and (max-width: 1024px) {
#b-fieldcode, #page {
-webkit-flex-flow: column;
flex-flow: column;
flex-direction: column;
}
#b-code, #b-field {
-webkit-order: 0;
order: 0;
}
#b-field, #b-code {
height: 500px;
}
}
<script type="text/javascript" src="http://codemirror.net/lib/codemirror.js"></script>
<div id="b-toolbox" class="b-section">
Here comes the space for buttons.
[PARAMS ALL] width: 100% of screen, height: sized to content
</div>
<div id="b-fieldcode">
<div id="b-field" class="b-section">
Here comes canvas wrapper.<br />
[PARAMS landscape] width: flex 40% of screen, height:
100% of screen minus b-toolbox and b-console.
<br />[PARAMS portrait] width: 100% of
screen, height: fixed 400px.<br />
<canvas width="300" height="300" id="canvas"
style="background-color: green" />
</div>
<div id="b-code" class="b-section">
Here comes CodeEditor wrapper.<br />
[PARAMS landscape] width: flex 60% of screen, height:
100% of screen minus b-toolbox and b-console.<br />
[PARAMS portrait] width: 100% of
screen, height: fixed 500px.
<div id="b-codemirror"></div>
</div>
</div>
<div id="b-console" class="b-section">
Here comes output console.
[PARAMS ALL] width: 100% of screen, height: fixed 120px.
</div>
First of all, you need to split styles for portrait and landscape. For portrait part, that's simple easy, so let's skip it.
For landspace part, you need a fluid height header (buttons) and a fixed height footer (console). This is a typical use case of css flex - all spare space are going to main part. So you just set display: flex; flex-direction: column; to <body> and flex: 1; to the main part (#fieldcode in your snippet).
Then #field occupies 40% width of #fieldcode, and #code ocuppies 60%. So again, you set display: flex; flex-direction: row; to #fieldcode, and flex: 4; to #field, flex: 6; to #code, so that spare space of #fieldcode is separated as 4:6. But please note the difference from previous. Yes, the flex-direction value is different. That tells the browser either to separate horizontally, or vertically.
html, body {
margin: 0;
padding: 0;
}
#toolbox {
background: #feb;
}
#field {
background: #ccf;
overflow: auto;
}
#code {
background: #dd8;
overflow: auto;
}
#codemirror {
min-width: 100%;
min-height: 100%;
}
#console {
background: #feb;
height: 120px;
}
#media screen and (orientation: portrait) {
#field {
height: 400px;
}
#code {
height: 500px;
}
}
#media screen and (orientation: landscape) {
html, body {
height: 100%;
}
body {
display: flex;
flex-direction: column;
}
#fieldcode {
flex: 1;
display: flex;
flex-direction: row;
}
#field {
flex: 4;
}
#code {
flex: 6;
}
}
<div id="toolbox">buttons here</div>
<div id="fieldcode">
<div id="field">
<canvas></canvas>
</div>
<div id="code">
<div id="codemirror"></div>
</div>
</div>
<div id="console">console here</div>