Reputation: 181
Context: I'm working through the Odin Project and trying to make an etch-a-sketch board. The project asks for you to make a board that you can draw on when your mouse hovers over, but it has to be made out of a grid of small divs that you add to the DOM from your javascript.
Problem: When the divs get generated to make the grid, they appear with a width of x (user generated) but a height of 0. So you can't hover over them. I expect to see a large blue square but instead it is blank unless I go out of my way to add in a height value in the css. The divs are created in the for-loop of line 14 of the javascript file here: https://jsfiddle.net/krmanski/ry12xumq/9/
function generateCanvas(gridSize){
//create the gridlines
//divide canvas into A x A where A = the number provided by user
let canvas = document.querySelector(".main-grid-container");
canvas.style.gridTemplateColumns = `repeat(${gridSize}, 1fr)`;
canvas.style.gridTemplateRows = `repeat(${gridSize}, 1fr)`;
alert("canvas should be generated");
let divsTotal = (gridSize * gridSize);
for(let i = 0; i < divsTotal; i++){
let div = document.createElement("div");
div.classList.add("grid-item");
div.style.backgroundColor="blue";
//this will allow our divs to change color when hovered over
div.addEventListener("mouseover", function(){
div.style.backgroundColor="black";
})
canvas.appendChild(div);
}
}
I have looked at other people's solutions on github and youtube and nearly all of them use the exact same code I do in my for-loop, and they apply no CSS at any point to tell their divs to have height. I am thinking of starting from a blank slate because I just can't figure out the problem but at this point I'm just idly curious what is the problem and why my divs are appearing with 0 height.
Upvotes: 1
Views: 73
Reputation: 1313
For some reason, your line ( I tried to figure the reason out, but couldn't )
// style.insertRule(`.grid-item {height: ${gridSize}}`,0);
doesn't select grid-items. but I found that you selected them when you added grid-item
class. so just add div.style.height = "100%";
after that.
//wait until the HTML and CSS are loaded before you run the javascript
document.addEventListener("DOMContentLoaded", function(){
generateCanvas(16);
console.log("dom content is loaded");
});
function generateCanvas(gridSize){
//create the gridlines
//divide canvas into A x A where A = the number provided by user
let canvas = document.querySelector(".main-grid-container");
canvas.style.gridTemplateColumns = `repeat(${gridSize}, 1fr)`;
canvas.style.gridTemplateRows = `repeat(${gridSize}, 1fr)`;
// alert("canvas should be generated");
// style.insertRule(`.grid-item {height: ${gridSize}}`,0);
let divsTotal = (gridSize * gridSize);
for(let i = 0; i < divsTotal; i++){
let div = document.createElement("div");
div.classList.add("grid-item");
div.style.backgroundColor="blue";
div.style.height = "100%";
//this will allow our divs to change color when hovered over
div.addEventListener("mouseover", function(){
div.style.backgroundColor="black";
})
canvas.appendChild(div);
}
}
function selectSize(){
//has the user type a number and returns that number, but only if it is between 0 and 100
let userInput = prompt("What should be the size of the board?")
let message = document.querySelector("#message")
if (userInput == ""){
message.innerText = "Please provide a number only";
} else if(userInput < 0 || userInput > 100){
message.innerText ="Please only provide a number between 1 and 100"
} else {
message.innerText =`You selected a ${userInput} x ${userInput} sized grid for your canvas`
generateCanvas(userInput);
}
}
const buttonPress = e =>{
//takes in the id of the button that was pressed.
let buttonID = e.target.id;
console.log(buttonID);
alert(`button ${buttonID} was pressed`);
switch(buttonID){
case "modify-grid":
selectSize();
break;
case "black":
alert('you pressed black');
break;
case "red":
alert('you pressed red');
break;
case "reset":
alert('you pressed reset');
break;
}
}
//get all buttons and make them listen for a click to run a function
let buttons = document.querySelectorAll(".button");
buttons.forEach(button => button.addEventListener("click", buttonPress));
@import url('https://fonts.googleapis.com/css?family=Muli&display=swap');
@import url('https://fonts.googleapis.com/css2?family=Comforter+Brush&display=swap');
@import url('https://fonts.googleapis.com/css?family=Quicksand&display=swap');
h3 {
font-family: 'Quicksand', sans-serif;
font-weight: 700;
font-style: normal;
letter-spacing: -.02em;
color: rgb(15, 45, 0);
font-size: 18px;
line-height: 1.15;
}
.header{
display: flex;
justify-content: center;
align-items: center;
padding: 10px;
margin: 20px;
border: solid;
border-color: black;
flex-direction: column;
}
.main-program-space{
display: flex;
justify-content: center;
align-items: center;
padding: 10px;
margin: 20px;
border: solid;
border-color: black;
flex-direction: column;
}
.buttons-flexbox{
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px;
margin: 20px;
border: solid;
border-color: red;
list-style: none;
flex-direction: row;
gap: 20px;
}
/* This will make our buttons look cool and change when hovered over */
.button {
align-items: center;
background-image: linear-gradient(144deg,#AF40FF, #5B42F3 50%,#00DDEB);
border: 0;
border-radius: 8px;
box-shadow: rgba(151, 65, 252, 0.2) 0 15px 30px -5px;
box-sizing: border-box;
color: #FFFFFF;
display: flex;
font-family: Phantomsans, sans-serif;
font-size: 20px;
justify-content: center;
line-height: 1em;
max-width: 100%;
min-width: 140px;
padding: 3px;
text-decoration: none;
user-select: none;
-webkit-user-select: none;
touch-action: manipulation;
white-space: nowrap;
cursor: pointer;
min-width: 150px;
min-height: 50px;
}
.button:active,
.button:hover {
outline: 0;
}
.main-grid-container{
display: grid;
justify-content: center;
align-items: center;
padding: 10px;
margin: 20px;
border: solid;
border-color: red;
width: 500px;
height: 500px;
}
/* .grid-item{
height: 12px;
} */
.bottom-text{
display: flexbox;
justify-content: center;
align-items: center;
padding: 10px;
margin: 20px;
border: solid;
border-color: red;
}
.footer-flexbox{
display: flexbox;
justify-content: center;
align-items: center;
padding: 10px;
margin: 20px;
border: solid;
border-color: black;
}
.footer{
display: flexbox;
justify-content: center;
align-items: center;
padding: 10px;
margin: 20px;
border: solid;
border-color: red;
}
<body>
<div class ="title header">
<h3>The html is working but what about CSS</h3>
<p id="message">(messages from main.js will print here)</p>
</div>
<div class="main-program-space">
<ul class="buttons-flexbox">
<li><button id="modify-grid" class="button modify-grid">Modify Grid</span></button></li>
<li><button id="black" class="button black">Black</button></li>
<li><button id="red" class="button red">Red</button></li>
<li><button id="reset" class="button reset">Reset</button></li>
</ul>
<div class="main-grid-container">
</div>
<div class="bottom-text">
<h3>XXXXX bottom text XXXXX</h3>
</div>
</div>
<div class="footer-flexbox">
<div class="footer">
<h3>XXXXX footer XXXXX</h3>
</div>
</div>
</body>
Upvotes: 0
Reputation: 33813
Is this the sort of effect that you were after? The following uses css variables to determine width/height of the individual grid squares based upon simple arithmetic of the canvas with divided by the number of grid-items. The CSS variables are updated within the generateCanvas
function and this can be extended to control the various colours presumably set by the buttons.
let active=true;
//wait until the HTML and CSS are loaded before you run the javascript
document.addEventListener("DOMContentLoaded", function() {
generateCanvas();
document.addEventListener('contextmenu',e=>{
e.preventDefault();
if( e.target.parentNode==document.querySelector(".main-grid-container") ){
active=false;
}
})
document.addEventListener('blur',()=>active=true);
document.addEventListener('click',()=>active=true);
});
function generateCanvas(size=16) {
// Find the doc root to access variables
let root = document.documentElement;
let canvas = document.querySelector(".main-grid-container");
canvas.style.gridTemplateColumns = `repeat(${size}, 1fr)`;
canvas.style.gridTemplateRows = `repeat(${size}, 1fr)`;
// important to clear the grid otherwise it will grow
// on each invocation of this function!
canvas.innerHTML = '';
// calculate the size of the containg canvas
let box = canvas.getBoundingClientRect();
let w = box.width / size;
let h = box.height / size;
// update the variables with new sizes
root.style.setProperty('--w', `${w}px`);
root.style.setProperty('--h', `${h}px`);
for( let i=0; i < Math.pow(size, 2); i++ ) {
let div = document.createElement("div");
div.classList.add("grid-item");
canvas.appendChild(div);
}
// Rather than assign the same event listener to every grid square, use a `delegated`
// event listener bound to the canvas.
canvas.addEventListener('mouseover',e=>{
let cn='grid-paint';
if( active && e.target.classList.contains('grid-item') && !e.target.classList.contains( cn ) )e.target.classList.add( cn )
})
}
function selectSize() {
//has the user type a number and returns that number, but only if it is between 0 and 100
let userInput = prompt("What should be the size of the board?")
let message = document.querySelector("#message")
if (isNaN( userInput ) ) {
message.innerText = "Please provide a number only";
} else if( Number(userInput) < 0 || Number(userInput) > 100) {
message.innerText = "Please only provide a number between 1 and 100"
} else {
message.innerText = `You selected a ${userInput} x ${userInput} sized grid for your canvas`
generateCanvas(userInput);
}
return true;
}
const setcolours=( fgcol='black', bgcol='blue' )=>{
let root = document.documentElement;
root.style.setProperty(`--fgcolour`,fgcol);
root.style.setProperty(`--bgcolour`,bgcol);
return true;
}
const reset=()=>{
generateCanvas();
return setcolours();
}
const buttonPress = e => {
let buttonID = e.target.id;
let alt=e.target.dataset.alt;
switch(buttonID) {
case "modify-grid":return selectSize();
case 'blue':return setcolours(alt,buttonID);
case "black":return setcolours(alt,buttonID);
case "red":return setcolours(alt,buttonID);
case "reset":return reset();
}
}
//get all buttons and make them listen for a click to run a function
let buttons = document.querySelectorAll(".button");
buttons.forEach(button => button.addEventListener("click", buttonPress));
@import url('https://fonts.googleapis.com/css?family=Muli&display=swap');
@import url('https://fonts.googleapis.com/css2?family=Comforter+Brush&display=swap');
@import url('https://fonts.googleapis.com/css?family=Quicksand&display=swap');
/*
Two variables to dictate width and height of grid elements.
These values are updated by javascript.
*/
:root {
--w:1px;
--h:1px;
--bgcolour:blue;
--fgcolour:black;
}
h3 {
font-family: 'Quicksand', sans-serif;
font-weight: 700;
font-style: normal;
letter-spacing: -.02em;
color: rgb(15, 45, 0);
font-size: 18px;
line-height: 1.15;
}
.header {
display: flex;
justify-content: center;
align-items: center;
padding: 10px;
margin: 20px;
border: solid;
border-color: black;
flex-direction: column;
}
.main-program-space {
display: flex;
justify-content: center;
align-items: center;
padding: 10px;
margin: 20px;
border: solid;
border-color: black;
flex-direction: column;
}
.buttons-flexbox {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
gap: 10px;
padding: 10px;
margin: 20px;
border: solid;
border-color: red;
list-style: none;
}
/* This will make our buttons look cool and change when hovered over */
.button {
align-items: center;
background-image: linear-gradient(144deg, #AF40FF, #5B42F3 50%, #00DDEB);
border: 0;
border-radius: 8px;
box-shadow: rgba(151, 65, 252, 0.2) 0 15px 30px -5px;
box-sizing: border-box;
color: #FFFFFF;
display: flex;
flex:1;
font-family: Phantomsans, sans-serif;
font-size: 1rem;
justify-content: center;
line-height: 1rem;
text-decoration: none;
user-select: none;
-webkit-user-select: none;
touch-action: manipulation;
white-space: nowrap;
cursor: pointer;
min-width: 130px;
min-height: 50px;
}
.button:active,
.button:hover {
outline: 0;
}
.main-grid-container {
display: grid;
justify-content: center;
align-items: center;
margin: 20px;
border: none;
width: 500px;
height: 500px;
padding:10px;
border:1px solid black;
}
.bottom-text {
display: flexbox;
justify-content: center;
align-items: center;
padding: 10px;
margin: 20px;
border: solid;
border-color: red;
}
.footer-flexbox {
display: flexbox;
justify-content: center;
align-items: center;
padding: 10px;
margin: 20px;
border: solid;
border-color: black;
}
.footer {
display: flexbox;
justify-content: center;
align-items: center;
padding: 10px;
margin: 20px;
border: solid;
border-color: red;
}
.grid-item {
display: flex;
flex: 1;
margin: 0;
background: var(--bgcolour);
width: var(--w);
height: var(--h);
}
.grid-paint{
background:var(--fgcolour);
}
<div class="title header">
<h3>The html is working but what about CSS</h3>
<p id="message">(messages from main.js will print here)</p>
</div>
<div class="main-program-space">
<ul class="buttons-flexbox">
<li><button id="modify-grid" class="button modify-grid">Modify Grid</button></li>
<li><button id="blue" data-alt='black' class="button blue">Blue</button></li>
<li><button id="black" data-alt='blue' class="button black">Black</button></li>
<li><button id="red" data-alt='yellow' class="button red">Red</button></li>
<li><button id="reset" class="button reset">Reset</button></li>
</ul>
<div class="main-grid-container"></div>
<div class="bottom-text">
<h3>XXXXX bottom text XXXXX</h3>
</div>
</div>
<div class="footer-flexbox">
<div class="footer">
<h3>XXXXX footer XXXXX</h3>
</div>
</div>
Upvotes: 0
Reputation: 2197
Setting align-items: center
on .main-grid-container
is what prevents your divs from being stretched vertically. I recommend simply removing that declaration, the initial value normal
will achieve the desired effect.
Upvotes: 2