skip to Main Content

I do Etch-a-Sketch – https://www.theodinproject.com/lessons/foundations-etch-a-sketch . But I want do something more than the assignment.

I need do this ONLY with Flexbox and JavaScript (without CSS Grid)

  1. When I do gridContainer.style.height = "100vh" , it is a little bit more than screen height. So I do 97vh. Is there another solution?

  2. I want add width=100vw (replace height = "97vh") ONLY for mobile screen. But I cannot do this with media query javasript. (The result is grid container height more than width.) Maybe I don’t know something? How can I do this?

<!DOCTYPE html>
<html lang="en">
<head>
    <link rel="stylesheet" href="./styles.css" />
    <script src="./script.js" defer></script>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Etch-a-Sketch</title>
</head>

<body>

<div id="gridUser">

    <h1>Etch-a-Sketch</h1>

    <form id="gridForm">

        <p><label for="gridInput">Enter a number of squares per side: 1...100</label></p>
        <p><input id="gridInput" type="text"></p>

        <p><legend>Choose mouse hover color</legend></p>
        <p>

            <input id="gridRadioYellow" name="gridRadio" value ="yellow" type="radio" checked>
            <label for="gridRadioYellow"> Yellow</label>

            <input id="gridRadioRandomize" name="gridRadio" value ="randomize" type="radio">
            <label for="gridRadioRandomize"> Randomize</label>

            <input id="gridRadioRandomizeEverySquare" name="gridRadio" value ="randomizeEverySquare" type="radio">
            <label for="gridRadioRandomizeEverySquare"> Randomize every square</label>

        </p>

        <p><button type="submit">Submit</button></p>

    </form>

    <div id="gridText"></div><br/>

</div>

<div id="gridContainer"></div>

</body>
</html>
* {
    box-sizing: border-box;
    font-family: Arial, sans-serif;
    text-align: center;
}

body {
    display: flex;
    flex-flow: row wrap;
    justify-content: flex-start;
}

#gridUser, #gridContainer {
    flex: 1 1 0%;
}

#gridInput {
    text-align: left;
}
// also add functional for yellow color (not randomize) and for randomize every square

let gridContainer = document.querySelector("#gridContainer");
let gridSize = 16*16;
let gridSquares = "";
let mouseSquares = [];
let mouseHoveringColor = "";

getGridPerSide();

function getGridPerSide() {

    let gridForm = document.querySelector("#gridForm");

    gridForm.addEventListener("submit", (e) => {
        e.preventDefault();

        let gridInput = document.querySelector("#gridInput");
        let gridRadio = document.querySelectorAll(`input[name="gridRadio"]`);
        let gridRadioChecked = "";
        let gridText = document.querySelector("#gridText");

        mouseHoveringColor = "";

        for (const gridRadioOne of gridRadio) {
            if (gridRadioOne.checked) {
                gridRadioChecked = gridRadioOne.value;
                break;
            } 
        }

        if (isNaN(gridInput.value) || gridInput.value < 1 || gridInput.value > 100) {
            gridText.innerHTML = `Enter a <em>right</em> number <strong>from 1 to 100</strong>`;
        } else if (gridRadioChecked === "yellow") {
            gridText.innerHTML = `
                The grid has <em>${gridInput.value}*${gridInput.value}</em> squares<br/>
                The mouse hover color is <strong>yellow</strong><br/>
            `;
            mouseHoveringColor = "yellow"; // value for doMouseHovering()
        } else if (gridRadioChecked === "randomize") {
            gridText.innerHTML = `
                The grid has <em>${gridInput.value}*${gridInput.value}</em> squares<br/>
                The mouse hover color is <strong>randomize</strong><br/>
            `;
            mouseHoveringColor = "randomize"; // value for doMouseHovering()
        } else {
            gridText.innerHTML = `
                The grid has <em>${gridInput.value}*${gridInput.value}</em> squares<br/>
                The mouse hover color is <strong>randomize every square</strong><br/>
            `;
            mouseHoveringColor = "randomizeEverySquare"; // value for doMouseHovering()
        }

        gridSize = gridInput.value * gridInput.value;

        createGrid();

    });
}

function createGrid() {

    gridContainer.innerHTML = ""; // grid clean for new submit

    for (let i=0; i < (gridSize); i++) {

        gridSquares = document.createElement("div");
        gridSquares.classList.add("gridSquares");
        gridContainer.appendChild(gridSquares);

        gridSquares.style.cssText = `
            width: calc(100% / ${gridInput.value});
            height: calc(100% / ${gridInput.value});
            background-color: #eee;
            border: 1px solid #ccc;
        `;

        gridContainer.style.cssText = `
            height: 97vh;
            width: auto;
            display: flex;
            flex-wrap: wrap;
            aspect-ratio: 1/1;
        `;

        mouseSquares.push(gridSquares); // create array for doMouseHovering()

    }

    doMouseHovering();

}

function doMouseHovering() {

// need mouseBackgroundColor for calculate "randomize" (NOT for "randomizeEverySquare")

    let mouseBackgroundColor = "";

    if (mouseHoveringColor === "yellow") {
        mouseBackgroundColor = "yellow";
    } else if (mouseHoveringColor === "randomize") {
        let r = Math.floor(Math.random() * 256);
        let g = Math.floor(Math.random() * 256);
        let b = Math.floor(Math.random() * 256);
        mouseBackgroundColor = `rgb(${r}, ${g}, ${b})`;
    }

    mouseSquares.forEach(gridSquares => {

        gridSquares.addEventListener('mouseover', () => {
            if (mouseHoveringColor === "yellow") {
                gridSquares.style.backgroundColor = mouseBackgroundColor;   
            } else if (mouseHoveringColor === "randomize") {
                gridSquares.style.backgroundColor = mouseBackgroundColor;
            } else {
                let r = Math.floor(Math.random() * 256);
                let g = Math.floor(Math.random() * 256);
                let b = Math.floor(Math.random() * 256);
                gridSquares.style.backgroundColor = `rgb(${r}, ${g}, ${b})`;
            }

        });

    });

}

I tried do this with CSS media query and JavaScript media query. The result is grid container height more than width. But the grid container must be square.

2

Answers


  1. Chosen as BEST ANSWER

    I found a simple solution. Change vh and vw on vmin. (And now I don't need media queries for mobile screens.)

    gridContainer.style.cssText = `
                height: 95vmin;
                width: 95vmin;
                margin-top: 1vmin;
    `;
    

  2. I managed to get it to fit within the container by using the gap: 0px property with the flex-box container.

    I also used CSS Object Model to calculate out the exact dimensions for each square to make sure that it fits within the container’s computed dimensions.

    There’s many different ways to do this… this was just one such way

    class XSquare extends HTMLElement {
      constructor() {
        super();
        //   this.style.backgroundColor = 'white';
        this.addEventListener('mouseenter', () => this.style.backgroundColor = 'black');
    
      }
    }
    
    customElements.define('x-square', XSquare);
    
    
    function createGrid(size) {
      const container = document.getElementById('container');
      container.innerHTML = ''; // Clear previous grid
      container.style.padding = 0 + 'px';
      container.style.margin = 0 + 'px';
      container.style.width = 100 + '%';
      container.style.height = 100 + '%';
      container.style.gridTemplateColumns = `repeat(${size}, 1fr)`;
    
      var containerWidth = container.attributeStyleMap.get("width").value;
      var containerHeight = container.attributeStyleMap.get("height").value;
      var sqSize = CSS.percent(Math.floor(Math.min(containerWidth / size, containerHeight / size)));
      container.style.height = sqSize * size;
      container.style.width = sqSize * size;
    
      for (let i = 0; i < size * size; i++) {
        const square = document.createElement('x-square');
    
        square.style.maxWidth = sqSize
        square.style.maxHeight = sqSize
        square.style.minWidth = sqSize
        square.style.minHeight = sqSize
       
        container.appendChild(square);
      }
    }
    
    document.getElementById('resize').addEventListener('click', () => {
      const newSize = prompt('Enter new grid size (max 100)', 16);
      if (newSize !== null && newSize <= 100) {
        createGrid(newSize);
      }
    });
    
    createGrid(16); // Initial grid creation
    #container {
      display: flex;
      flex-wrap: wrap;
      flex: 0 0 0 0;
      width: 101%;
      /* Fixed width for the container */
      height: 99%;
      margin: 0px;
      padding: 0px;
      border: 2px solid black;
       // make gap between items 0px
       gap: 0px 
    }
    
    x-square {
      aspect-ratio: 1;
      /* Ensures squares remain square */
      border: 1px solid black;
      transition: background-color 0.3s;
      /* Smooth color transition */
      box-sizing: border-box;
      max-width: 20px;
      max-height: 20px;
      margin: 0px;
      padding: 0px;
     
    }
    
    x-square:hover {
      background-color: black;
      /* Color change on hover */
    }
    <!DOCTYPE html>
    <html lang="en">
    
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Dynamic Etch-A-Sketch</title>
    
    </head>
    
    <body>
      <button id="resize">Resize Grid</button>
      <div id="container"></div>
    
    
    </body>
    
    </html>

    You could even create the canvas from javascript using document.createElement("canvas") at the start.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search