CSS equal number of columns on each row for responsive design - javascript

I am working on a control panel that has 36 buttons. It is possible to add more buttons in the future, but the total number will always be even. I want the buttons to have the same width and height and to resize in the container when the user resizes the browser window.
On big screens there will be one row like this:
On laptop will be like this:
On tablet or smaller screens will be like this:
I have fixed with media queries for specific screens but problems happen if the user resizes the window (wants to see multiple windows at the same time). It is difficult to set tens of media queries. I am looking for a more general solution.
This is what I do not want to see on my site:
This is the snippet I am working on. I have tried both flex and grid approaches, but with no success.
insertButtons("flex-container")
insertButtons("grid-container")
function insertButtons(containerId) {
let container = document.getElementById(containerId)
let number = 36
var i;
for (i = 0; i < number; i++) {
let button = document.createElement("button")
button.innerHTML = i+1
if (containerId == "flex-container") {
button.classList.add("element-button")
}
container.appendChild(button)
}
}
.container {
background: black;
position: relative;
margin-top: 20px;
width: 96vw;
left: 50%;
transform: translate(-50%, 0);
padding: 5pt;
}
#flex-container {
display: flex;
flex-wrap: wrap;
}
#grid-container {
padding: 5pt;
background: black;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(32pt, 1fr));
grid-auto-rows: 30pt;
grid-gap: 3pt;
}
.element-button {
margin: 2pt;
padding: 2pt;
flex-grow: 1;
height: 30pt;
min-width: 20pt;;
}
button {
border-radius: 3pt;
font-size: 1.2em;
}
<h1 align="center">Flex</h1>
<div id="flex-container" class="container"></div>
<h1 align="center">Grid</h1>
<div id="grid-container" class="container"></div>
Thank you!

Related

Is there a way to resize grid boxes?

I have a react app where I'm creating about a million grid boxes, all the boxes ought to fit into the immediate screen (I want each box to be tiny asf). I'm using js to calculate each box's height and width in relation to the number of boxes.
var numOfBoxes = 1000 // this number can change anytime
var [height, width] = `${100/numberOfBoxes}%`
I created the grid using a CSS I found on StackOverflow
#root {
width: 100vw;
height: 100vh
}
// I tried to use vh and vw to make the #root element fit the initial screen
.square-container {
display: flex;
height: 100%;
width: 100%;
flex-wrap: wrap;
}
.square {
position: relative;
flex-basis: calc(25% - 10px);
margin: 5px;
border: 1px solid;
box-sizing: border-box;
}
.square::before {
content: '';
display: block;
padding-top: 100%;
}
.square .content {
position: absolute;
top: 0; left: 0;
height: 100%;
width: 100%;
}
But the squares remain the same size when I try to increase or decrease numOfBoxes. I tried changing the height and width from the DevTools but to no avail.
It looks like this if I render 100 boxes or 1000
Can someone point me in the right direction?
You can add a CSS variable to the root element, use it as part of the grid class, and then update it with setProperty.
// Using a setTimeout for this demo, but you would
// be adding this to your render method I expect
function changeWidth(width, count = 1) {
document.documentElement.style.setProperty('--square-width', `${width}px`);
if (count < 5) setTimeout(changeWidth, 2000, width +=5, ++count)
}
changeWidth(5);
:root {
--square-width: 10px
}
.container {
display: grid;
grid-template-columns: repeat(3, var(--square-width));
grid-gap: 5px;
}
.container div {
background-color: red;
aspect-ratio: 1;
}
<div class="container">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>

HTML - Fitting images in multiple rows to fit viewport

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;
}
}
}

Adding non-centered text shifts centered elements [duplicate]

This question already has answers here:
How to prevent scrollbar from repositioning web page?
(26 answers)
Closed 4 years ago.
After putting a centered header, I add a non-centered output with JS. After the output is produced, the header shifts a bit left. What can be done to tackle this problem?
let output = [];
function spit() {
for (let i = 0; i < 100; i++) {
output.push(i);
}
document.getElementById("output").innerHTML =
output.join("<br>");
}
.header {
background-color: lightgray;
border: none;
color: black;
padding: 17px 25px;
display: block;
text-align: center;
font-size: 36px;
width: 100%;
margin-left: auto;
margin-right: auto;
}
<h2 id="dictName" class="header">
Testing Page
</h2>
<button style="font-size:20pt;height:35pt" onclick="spit()">
Press me!
</button>
<p id="output">
</p>
One crazy solution might be to set you body height to the view port height, that way you start off with a scroll, avoiding the shift when the button gets pressed.
let output = [];
function spit() {
for (let i = 0; i < 100; i++) {
output.push(i);
}
document.getElementById("output").innerHTML =
output.join("<br>");
}
body {
min-height: 100vh;
}
.header {
background-color: lightgray;
border: none;
color: black;
padding: 17px 25px;
display: block;
text-align: center;
font-size: 36px;
width: 100%;
margin-left: auto;
margin-right: auto;
}
<h2 id="dictName" class="header">
Testing Page
</h2>
<button style="font-size:20pt;height:35pt" onclick="spit()">
Press me!
</button>
<p id="output">
</p>
I added a universal { margin:0; padding:0;} to your css code. The code did seem to be centered but I think the margin of -50 (that's being created by the auto margin ) is throwing off the look.
let output = [];
function spit() {
for (let i = 0; i < 100; i++) {
output.push(i);
}
document.getElementById("output").innerHTML =
output.join("<br>");
}
* {
margin: 0px; padding:0px;
}
button {
/*margin-left:15px;*/
margin-top:7px;
font-size: 20pt;
height: 35pt;
}
.header {
background-color: lightgray;
/* border: 15px solid white;*/ /*use the commented props if you still want the "indented" effect" */
color: black;
padding: 17px 25px;
display: block;
text-align: center;
font-size: 36px;
width: 100%;
margin-right:auto;
margin-left:auto;
}
<h2 id="dictName" class="header">
Testing Page
</h2>
<button onclick="spit()">
Press me!
</button>
<p id="output">
</p>
IF you don't want the h1 to shift due to the scrollbar, you would have to calculate, using css calc() (and maybe some other things too), 50vw - (widthOfH1/2). This works because the vw unit (viewport width) is not affected by the scrollbar.
One way for the scrollbar to not affect the centering of the h1 would be to use JQuery.
$(#dictName).style.marginLeft = 'calc(50vw -'+(this.width/2)+'px)';
I haven't tested this so I'm not 100% sure if it will work, but please tell me if it does or doesn't. You may need to rerun this code when the button is pressed.
After some googling it seems I found the easiest way to solve this problem here, on SO:
How to prevent scrollbar from repositioning web page?
html {
overflow-y: scroll;
}
Probably, the question should be closed as duplicate, but I don't have enough reputation to do it.

Seamless onClick animated <div>s

I'm creating a portfolio website for a photographer. The idea is to have 3 main sections, animated on click. When you click on any of those it will take about 80% space revealing itself and pushing others to the side(s). They will be packed with content like albums, text, images etc. It has to be seamless transitions between those 3 and any clickable item inside. that's the question itself: how do i achieve that, i suppose it has to be JS, maybe there is ready framework for that feature? Check out pic below for better understanding
Use this as the basis to fit it to you use-case. Works on hover on any section.
Snippet:
* { box-sizing: border-box; margin: 0; padding: 0; font-family: sans-serif; }
.parent {
width: 100vw; height: 120px;
display: flex;
flex-direction: columns;
}
.parent > div {
background-color: #ddd; text-align: center; padding: 12px 8px;
flex: 1 1 10%;
transition: all 500ms;
}
.parent > div:hover {
flex: 1 1 80%;
}
.parent > div:first-child { background-color: #d33; }
.parent > div:last-child { background-color: #33d; }
<div class="parent">
<div>1</div>
<div>2</div>
<div>3</div>
</div>

Using CSS display:flex (flexbox) and/or JavaScript to make adjustable page

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>

Categories

Resources