I created a 16 x 16 grid where I can etch a sketch on that grid. It's working well. However, the problem now is that, my 16x16 grid is not hold in a container where I append it. Isn't it supposed to contain in the container where I append it ? I want to display the grid in a way like it's in a big squared box and empty on the inside. Only the most outer border is displayed. So that way, the user will know intuitively they'll have to hover over the box to sketch.
let container = document.querySelector('.container');
let rows = document.getElementsByClassName('gridRow');
let columns = document.getElementsByClassName('gridColumn');
function createGrid(number) {
makeRow(number);
makeColumn(number);
}
function makeRow(numberOfRow) {
for (let i = 0; i < numberOfRow; i++) {
let row = document.createElement('div');
container.appendChild(row);
row.classList.add('gridRow');
}
}
function makeColumn(numberOfColumn) {
for (let i = 0; i < rows.length; i++) {
for (let j = 0; j < numberOfColumn; j++) {
let column = document.createElement('div');
column.addEventListener('mouseenter', () => {
column.classList.add('colored');
});
// column.addEventListener('mouseleave', () => {
// column.classList.remove('colored');
// })
rows[j].appendChild(column);
column.classList.add('gridColumn');
}
}
}
createGrid(16);
#import url('https://fonts.googleapis.com/css2?family=Asap:wght#400;600;700&display=swap');
body {
display: flex;
flex: 1;
height: 100%;
flex-direction: column;
background-color: beige;
font-family: Asap, sans-serif;
margin: 0;
padding: 0;
height: 100%;
width: 100%;
}
.header {
display: flex;
flex: 1;
justify-content: center;
}
#setGridSize {
display: inline-flex;
justify-content: center;
flex: 1;
gap: 12px;
}
#guide {
text-align: center;
margin: 1px;
font-family: Asap, sans-serif;
color: red;
font-size: 13px;
;
}
.container {
display: flex;
flex: 1;
border: 2px solid grey;
justify-content: center;
align-content: center;
}
.gridColumn {
display: inline-flex;
flex: 1;
border: 1px solid beige;
margin: -2px 0px;
width: 100%;
height: 10%;
}
.colored {
background: red;
}
.buttons {
display: flex;
flex: 1;
gap: 20px;
}
<h1 class="header"> Let's sketch ! </h1>
<div id="setGridSize">
<p> Grid size </p> <input type="text" placeholder="Size of Board" class="size-box">
<button id="submit"> Submit </button>
</div>
<p id="guide"> Enter a number between 2 to 99</p>
<div class="container"></div>
<div class="buttons">
<button id="white"> White </button>
<button id="eraser"> Eraser </button>
<button id="black"> Black </button>
<button id="rainbow"> Rainbow </button>
<button id="reset"> Reset</button>
</div>
Try it: change height to fixed value.
.gridColumn {
display: inline-flex;
flex: 1;
border: 1px solid beige;
margin: -2px 0px;
width: 100%;
height: 20px;
}
let container = document.querySelector('.container');
let rows = document.getElementsByClassName('gridRow');
let columns = document.getElementsByClassName('gridColumn');
function createGrid(number) {
makeRow(number);
makeColumn(number);
}
function makeRow(numberOfRow) {
for (let i = 0; i < numberOfRow; i++) {
let row = document.createElement('div');
container.appendChild(row);
row.classList.add('gridRow');
}
}
function makeColumn(numberOfColumn) {
for (let i = 0; i < rows.length; i++) {
for (let j = 0; j < numberOfColumn; j++) {
let column = document.createElement('div');
column.addEventListener('mouseenter', () => {
column.classList.add('colored');
});
// column.addEventListener('mouseleave', () => {
// column.classList.remove('colored');
// })
rows[j].appendChild(column);
column.classList.add('gridColumn');
}
}
}
createGrid(16);
#import url('https://fonts.googleapis.com/css2?family=Asap:wght#400;600;700&display=swap');
body {
display: flex;
flex: 1;
height: 100%;
flex-direction: column;
background-color: beige;
font-family: Asap, sans-serif;
margin: 0;
padding: 0;
height: 100%;
width: 100%;
}
.header {
display: flex;
flex: 1;
justify-content: center;
}
#setGridSize {
display: inline-flex;
justify-content: center;
flex: 1;
gap: 12px;
}
#guide {
text-align: center;
margin: 1px;
font-family: Asap, sans-serif;
color: red;
font-size: 13px;
;
}
.container {
display: flex;
flex: 1;
border: 2px solid grey;
justify-content: center;
align-content: center;
}
.gridColumn {
display: inline-flex;
flex: 1;
border: 1px solid beige;
margin: -2px 0px;
width: 100%;
height: 20px;
}
.colored {
background: red;
}
.buttons {
display: flex;
flex: 1;
gap: 20px;
}
<h1 class="header"> Let's sketch ! </h1>
<div id="setGridSize">
<p> Grid size </p> <input type="text" placeholder="Size of Board" class="size-box">
<button id="submit"> Submit </button>
</div>
<p id="guide"> Enter a number between 2 to 99</p>
<div class="container"></div>
<div class="buttons">
<button id="white"> White </button>
<button id="eraser"> Eraser </button>
<button id="black"> Black </button>
<button id="rainbow"> Rainbow </button>
<button id="reset"> Reset</button>
</div>
Related
When iam dropping my div with an image inside i get nothing and after i am trying to get it ID i get null of course. But how can i get info from a div with image and append row with it?
Code here or check codepen:
https://codepen.io/13reathcode/pen/NWBmZpb
'use strict';
let queuedImagesArray = [],
queuedForm = document.querySelector('#queued-form'),
queuedDiv = document.querySelector('.queued-div'),
inputDiv = document.querySelector('.input-div'),
input = document.querySelector('.input-div input');
const colors = ['#FF7F7F', '#FFBF7F', '#FFDF7F', '#BFFF7F', '#7FFF7F', '#7FBFFF', '#7F7FFF'],
rows = document.querySelectorAll('.content__row'),
cards = document.querySelectorAll('.content__card'),
addCard = document.getElementById('addCard');
// Queued Images
const onDragStart = (event) => {
console.log('Dragging');
event.dataTransfer.setData('id', event.target.id);
setTimeout(() => {
event.target.style.visibility = 'hidden';
}, 100);
};
const onDragEnd = (event) => {
console.log('Ended dragging');
event.target.style.visibility = 'visible';
};
const displayQueuedImages = () => {
let images = '';
queuedImagesArray.forEach((image, index) => {
images += `
<div class="image" draggable="true" id="${(Date.now() + '').slice(-10) + index}">
<img width='100' height='100' style="pointerEvents:none;" id="${index}" ondragstart="onDragStart" ondragend="onDragEnd"
src="${URL.createObjectURL(image)}" alt="image" />
<span style="color:black;font-size:2rem" onclick="deleteQueuedImage(${index})">×</span>
</div>
`;
});
queuedDiv.innerHTML = images;
};
const deleteQueuedImage = (index) => {
queuedImagesArray.splice(index, 1);
displayQueuedImages();
};
input.addEventListener('change', () => {
const files = input.files;
for (let i = 0; i < files.length; i++) {
queuedImagesArray.push(files[i]);
}
queuedForm.reset();
displayQueuedImages();
});
inputDiv.addEventListener('drop', (e) => {
e.preventDefault();
const files = e.dataTransfer.files;
for (let i = 0; i < files.length; i++) {
if (!files[i].type.match('image')) return;
if (queuedImagesArray.every((image) => image.name !== files[i].name))
queuedImagesArray.push(files[i]);
}
displayQueuedImages();
});
const onDrag = (event) => {
event.preventDefault();
};
// Problem here
const onDrop = (event) => {
event.preventDefault();
const draggedCardId = event.dataTransfer.getData('id'); // nothing
const draggedCard = document.getElementById(draggedCardId); // null
event.target.appendChild(draggedCard);
};
rows.forEach((row, index) => {
const label = row.querySelector('.content__label');
label.style.backgroundColor = colors[index];
row.ondragover = onDrag;
row.ondrop = onDrop;
});
<main>
<section class="section" id="section--1">
<div class="section__title">
<h2 class="section__description">Tier list app</h2>
<h3 class="section__text">Start dragging to move cards</h3>
</div>
<div class="content" id="content">
<div class="content__row">
<div class="content__label">S (The best)</div>
</div>
<div class="content__row">
<div class="content__label">A (Great)</div>
</div>
<div class="content__row">
<div class="content__label">B (Good)</div>
</div>
<div class="content__row">
<div class="content__label">C (Mediocre)</div>
</div>
<div class="content__row">
<div class="content__label">D (Bad)</div>
</div>
<div class="content__row">
<div class="content__label">E (Horrible)</div>
</div>
<!-- <div class="content__row">
<div class="content__label">F (Worst^_^)</div>
</div> -->
</div>
</section>
<form id="queued-form">
<div class="queued-div"></div>
</form>
<div class="input-div">
<p>Drag & drop images here or <span class="browse">Browse</span></p>
<input
type="file"
class="file"
multiple="multiple"
accept="image/png, image/jpeg, image/jpg"
/>
</div>
</main>
* {
margin: 0;
padding: 0;
box-sizing: inherit;
}
html {
font-size: 62.5%; // 10px = 1rem
box-sizing: border-box;
}
body {
font-family: 'Open Sans', sans-serif;
font-weight: 300;
color: #555;
line-height: 1.5;
}
.input-div {
width: 70%;
height: 200px;
border-radius: 5px;
display: flex;
justify-content: center;
align-items: center;
text-align: center;
margin: 5rem auto;
border: 2px dotted black;
background-color: white;
position: relative;
.browse {
color: black;
font-weight: bold;
}
}
.file {
width: 100%;
height: 100%;
position: absolute;
opacity: 0;
cursor: pointer;
}
.queued-div {
width: 70%;
min-height: 200px;
display: flex;
margin: 5rem auto;
justify-content: flex-start;
flex-wrap: wrap;
gap: 0.5rem;
position: relative;
border-radius: 5px;
border: 2px dotted black;
background-color: white;
.image {
height: 10rem;
border-radius: 5px;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.15);
overflow: hidden;
position: relative;
&:nth-child(4n) {
margin-right: 0;
}
img {
height: 100%;
width: 100%;
}
span {
position: absolute;
top: -4px;
right: 4px;
cursor: pointer;
font-size: 22px;
color: white;
&:hover {
opacity: 0.8;
}
}
}
}
#mixin center {
display: flex;
justify-content: center;
align-items: center;
}
// SECTIONS
.section {
padding: 1.8rem 3rem;
&__title {
max-width: 80rem;
margin: 0 auto 2rem auto;
text-align: center;
text-transform: uppercase;
}
&__description {
color: lightgreen;
font-size: 1.8rem;
}
&__text {
font-size: 2.5rem;
}
&__button {
font-size: 2rem;
text-transform: uppercase;
text-decoration: none;
padding: 1rem 2rem;
display: inline-block;
border-radius: 3rem;
position: relative;
background-color: lightgreen;
color: #fff;
border: none;
cursor: pointer;
}
}
// CONTENT
.content {
width: 70vw;
min-height: 10vh;
padding: 0rem;
box-sizing: content-box;
border: 3px solid #000;
display: flex;
flex-wrap: wrap;
flex-direction: column;
margin: 0 auto;
&__row {
width: 100%;
box-sizing: content-box;
flex-wrap: wrap;
height: 8.5rem;
background-color: #1a1a17;
display: flex;
&:not(:last-child) {
border-bottom: 2px solid #000;
}
}
&__label {
font-size: 2rem;
font-weight: 400;
height: 100%;
width: 15rem;
background-color: #555;
color: #333;
border-right: 3px solid #000;
#include center;
}
&__card {
#include center;
&:focus,
&:active {
cursor: pointer;
}
}
}
When i was adding images one by one everything was fine but when i changed button to input zone i can't get anything from new images.
There is a small issue in how you create your img elements: the ondragstart and ondragend event handlers aren't being assigned properly.
Currently, your img elements look something like:
<img id="0" ondragstart="onDragStart" ondragend="onDragEnd" src=... />
However, setting ondragstart to equal onDragStart doesn't actually invoke the function when the event is fired. Same with ondragend and onDragEnd. To do so, you have to actually invoke the functions with onDragStart(event) and onDragEnd(event).
This is because every HTML event handler attribute is implicitly wrapped in:
(event) => { /** the attribute value */ }
In other words, currently, your handlers are equivalent to:
(event) => { onDragStart }
// and
(event) => { onDragEnd }
instead of
(event) => { onDragStart(event) }
// and
(event) => { onDragEnd(event) }
which is given by
<img id="0" ondragstart="onDragStart(event)" ondragend="onDragEnd(event)" src=... />
So the fix is simply to fix the img generation code to:
images += `
<div class="image" draggable="true" id="${(Date.now() + '').slice(-10) + index}">
<img width='100' height='100' id="${index}"
ondragstart="onDragStart(event)" ondragend="onDragEnd(event)"
src="${URL.createObjectURL(image)}" alt="image" />
<span style="color: black; font-size: 2rem"
onclick="deleteQueuedImage(${index})">×</span>
</div>`;
I have been working on this for a little while, and I think I'm stuck at this point.
I made a div slider with arrows. Each div slide is set to a min-width of 80px.
The code works just fine, except, when I navigate either to the left or the right, it stops at the last item. I want this slider to loop (as in endlessly), instead of ending at the last item.
let buttonLeft = document.getElementById('slide_left')
let buttonRight = document.getElementById('slide_right')
buttonLeft.addEventListener('click', function() {
document.getElementById('slider').scrollLeft -= 90
})
buttonRight.addEventListener('click', function() {
document.getElementById('slider').scrollLeft += 90
})
body{
background-color: #555;
height: 100vh;
display: grid;
align-items: center;
justify-items: center;
font-family: 'Helvetica';
}
div#slide_wrapper{
width: 440px;
display: flex;
justify-content: space-between;
height: fit-content;
}
div#slider{
width: 350px;
display: flex;
height: fit-content;
flex-wrap: nowrap;
overflow: hidden;
}
div.thumbnail{
min-width: 80px;
min-height: 80px;
cursor: pointer;
display: grid;
place-items: center;
font-size: 30px;
}
div.thumbnail:not(:last-child){
margin-right: 10px;
}
div.thumbnail:nth-child(1){
background-color: darkturquoise;
}
div.thumbnail:nth-child(2){
background-color: goldenrod;
}
div.thumbnail:nth-child(3){
background-color: rebeccapurple;
}
div.thumbnail:nth-child(4){
background-color: powderblue;
}
div.thumbnail:nth-child(5){
background-color: firebrick;
}
div.thumbnail:nth-child(6){
background-color: sienna;
}
div.thumbnail:nth-child(7){
background-color: bisque;
}
div.thumbnail:nth-child(8){
background-color: navy;
}
div#slide_wrapper > button{
height: fit-content;
align-self: center;
font-size: 24px;
font-weight: 800;
border: none;
outline: none;
}
div#slide_wrapper > button:hover{
cursor: pointer;
background-color: dodgerblue;
color: #fff;
}
<div id="slide_wrapper">
<button id="slide_left" class="slide_arrow">❮</button>
<div id="slider">
<div class="thumbnail active">1</div>
<div class="thumbnail">2</div>
<div class="thumbnail">3</div>
<div class="thumbnail">4</div>
<div class="thumbnail">5</div>
<div class="thumbnail">6</div>
<div class="thumbnail">7</div>
<div class="thumbnail">8</div>
</div>
<button id="slide_right" class="slide_arrow">❯</button>
</div>
Nice slider! There are several ways to achieve what you want. In my opinion, the simplest solution would be to work with some if conditions and a counter variable. Once the number of thumbnails is reached, set the counter back to 0.
Update
Regarding to your comment. "How about doing the same for the left arrow.". In the if condition block: if (0 == slideCount) { i add these lines:
slideCount = thumbnail.length // set the slideCounter to maximum
document.getElementById('slider').scrollLeft = slideCount * 90 // calculate the scroll distance
slideCount--; // decrease slidecount
setActive(); // set the red border on the current slide
const buttonLeft = document.getElementById('slide_left')
const buttonRight = document.getElementById('slide_right')
const thumbnail = document.querySelectorAll(".thumbnail");
let slideCount = 0;
setActive();
buttonLeft.addEventListener('click', function() {
if (0 == slideCount) {
slideCount = thumbnail.length
document.getElementById('slider').scrollLeft = slideCount * 90
slideCount--;
setActive();
return;
}
slideCount--;
document.getElementById('slider').scrollLeft -= 90
setActive();
})
buttonRight.addEventListener('click', function() {
slideCount++;
if ( 8 == slideCount) {
document.getElementById('slider').scrollLeft = 0
slideCount = 0;
} else {
document.getElementById('slider').scrollLeft += 90
}
setActive();
})
function setActive() {
thumbnail.forEach(t => {
t.classList.remove("active");
})
thumbnail[slideCount].classList.add("active")
}
function count() {
console.log(slideCount);
}
body{
background-color: #555;
height: 100vh;
display: grid;
align-items: center;
justify-items: center;
font-family: 'Helvetica';
}
div#slide_wrapper{
width: 440px;
display: flex;
justify-content: space-between;
height: fit-content;
}
div#slider{
width: 350px;
display: flex;
height: fit-content;
flex-wrap: nowrap;
overflow: hidden;
}
div.thumbnail{
min-width: 80px;
min-height: 80px;
cursor: pointer;
display: grid;
place-items: center;
font-size: 30px;
}
div.thumbnail:not(:last-child){
margin-right: 10px;
}
div.thumbnail:nth-child(1){
background-color: darkturquoise;
}
div.thumbnail:nth-child(2){
background-color: goldenrod;
}
div.thumbnail:nth-child(3){
background-color: rebeccapurple;
}
div.thumbnail:nth-child(4){
background-color: powderblue;
}
div.thumbnail:nth-child(5){
background-color: firebrick;
}
div.thumbnail:nth-child(6){
background-color: sienna;
}
div.thumbnail:nth-child(7){
background-color: bisque;
}
div.thumbnail:nth-child(8){
background-color: navy;
}
div#slide_wrapper > button{
height: fit-content;
align-self: center;
font-size: 24px;
font-weight: 800;
border: none;
outline: none;
}
div#slide_wrapper > button:hover{
cursor: pointer;
background-color: dodgerblue;
color: #fff;
}
.active {
border: 2px solid red;
}
<div id="slide_wrapper">
<button id="slide_left" class="slide_arrow">❮</button>
<div id="slider">
<div class="thumbnail active">1</div>
<div class="thumbnail">2</div>
<div class="thumbnail">3</div>
<div class="thumbnail">4</div>
<div class="thumbnail">5</div>
<div class="thumbnail">6</div>
<div class="thumbnail">7</div>
<div class="thumbnail">8</div>
</div>
<button id="slide_right" class="slide_arrow">❯</button>
</div>
Just find the width of the slider and compare it with the scroll left like
let buttonLeft = document.getElementById('slide_left')
let buttonRight = document.getElementById('slide_right')
buttonLeft.addEventListener('click', function() {
document.getElementById('slider').scrollLeft -= 90
})
buttonRight.addEventListener('click', function() {
const elem = document.getElementById('slider');
const ElemWidth = elem.getClientRects()[0].width
if(document.getElementById('slider').scrollLeft > ElemWidth ){
document.getElementById('slider').scrollLeft = 0
}else{
document.getElementById('slider').scrollLeft += 90
}
console.log(ElemWidth, document.getElementById('slider').scrollLeft , document.getElementById('slider').scrollLeft > ElemWidth)
})
I need some advice.
After loading a new line, the copy button for other lines does not work for me. It always copies only the first link, even if I click on another button.
Thank for any advice.
Hi, I need some advice.
After loading a new line, the copy button for other lines does not work for me. It always copies only the first link, even if I click on another button.
Thank for any advice.
const container = document.querySelector(".container");
const inputField = container.querySelector("input");
var button = container.querySelector("button");
const showData = document.querySelector(".showData");
button.addEventListener("click", () =>{
const linkInput = inputField.value;
// console.log(linkInput);
fetch(`https://api.shrtco.de/v2/shorten?url=${linkInput}`)
.then(res => res.json())
.then(data =>{
// console.log(data)
inputField.value = "";
var apiData = `
<div class="data">
<h5>${data.result.short_link}</h5>
<button onclick="copyButton()" class="button__copy">Copy</button>
</div>
`;
showData.insertAdjacentHTML('afterbegin', apiData);
})
});
// Copy to clipboard
const element = document.querySelector(".link__item__button");
function copyButton() {
const cb = navigator.clipboard;
const shortLink = document.querySelector('.link__item__short');
cb.writeText(shortLink.innerText);
}
*{
font-family: sans-serif;
box-sizing: border-box;
margin: 0;
padding: 0;
}
.container{
width: 100%;
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
}
input{
width: 200px;
height: 50px;
border-radius: 1rem;
margin-top: 1rem;
text-align: center;
border: 3px solid blue;
}
button{
width: 200px;
height: 50px;
border-radius: 1rem;
border: 0;
outline: 0;
margin-top: 1rem;
cursor: pointer;
}
.showData {
margin: 30px 0 0 0;
line-height: 3;
}
.data{
display: flex;
align-items: center;
margin-top: 10px;
}
.data .button__copy{
width: 100px;
height: 40px;
background: lightblue;
margin: 0 0 0 1rem;
}
<header>
<div class="container">
<h1>Short URL Generator</h1>
<input type="text" placeholder="paste your long link here">
<button>Create a Link</button>
<div class="showData">
</div>
</div>
</header>
The copy function does not work here in code snippet or on online sites with an iframe because of safety policy.
If you create a page without one, works fine. I checked.
const container = document.querySelector(".container");
const inputField = container.querySelector("input");
const button = container.querySelector("button");
const showData = document.querySelector(".showData");
button.addEventListener("click", () =>{
const linkInput = inputField.value;
fetch(`https://api.shrtco.de/v2/shorten?url=${linkInput}`)
.then(res => res.json())
.then(data =>{
inputField.value = "";
const shortLink = data.result.short_link
const id = shortLink.substring(shortLink.lastIndexOf('/') + 1)
const apiData = `
<div class="data">
<h5 id="${id}">${shortLink}</h5>
<button onclick="copyButton('${id}')" class="button__copy">Copy</button>
</div>
`;
showData.insertAdjacentHTML('afterbegin', apiData);
})
});
function copyButton(id) {
const shortLink = document.querySelector('#' + id);
navigator.clipboard.writeText(shortLink.innerText).then(() => {
console.log('Async: Copying to clipboard was successful!');
}, (err) => {
console.error('Async: Could not copy text: ', err);
});
}
*{
font-family: sans-serif;
box-sizing: border-box;
margin: 0;
padding: 0;
}
.container{
width: 100%;
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
}
input{
width: 200px;
height: 50px;
border-radius: 1rem;
margin-top: 1rem;
text-align: center;
border: 3px solid blue;
}
button{
width: 200px;
height: 50px;
border-radius: 1rem;
border: 0;
outline: 0;
margin-top: 1rem;
cursor: pointer;
}
.showData {
margin: 30px 0 0 0;
line-height: 3;
}
.data{
display: flex;
align-items: center;
margin-top: 10px;
}
.data .button__copy{
width: 100px;
height: 40px;
background: lightblue;
margin: 0 0 0 1rem;
}
<div class="container">
<h1>Short URL Generator</h1>
<input type="text" placeholder="paste your long link here">
<button>Create a Link</button>
<div class="showData"></div>
</div>
I am creating a battleship game for my next project to learn javascript and I am attempting to create divs to fill up a container wrapper. I do not want the divs to overflow, only to fill up the remaining space until it is filled. How do I test for the empty space remaining within a div to continue adding in my loop until the container is filled?
My container I am trying to fill is the #wrapper. My loop in javascript is creating the divs. I want to create a condition for the loop to stop filling when the container is full (i = 0; i < ?; i++). How do I test for this?
const body = document.querySelector('body');
const wrapper = document.querySelector('#wrapper')
const box = document.getElementsByClassName('.box');
const div = document.querySelector('div');
for (i = 0; i < 250; i++) {
let div = document.createElement('div');
div.classList = 'squares';
wrapper.appendChild(div);
}
const destroyer1 = document.querySelector('#destroyer1');
const destroyer2 = document.querySelector('#destroyer2');
destroyer1.addEventListener("drag", function(event) {}, false);
destroyer1.addEventListener("dragstart", function(event) {}, false);
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body,
html {
height: 100%;
width: 100%;
}
body {
display: flex;
flex-direction: column;
align-items: center;
background-color: rgb(0, 0, 0);
}
h1 {
color: white;
}
#messageBoard {
color: white;
}
#shipContainer {
width: 100%;
height: 15rem;
top: 0;
left: 0;
background-color: rgb(41, 25, 25);
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
#wrapper {
width: 100%;
height: 30rem;
padding: 5rem;
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-content: flex-start;
}
.squares {
border: 1px solid blue;
width: 5%;
height: 5%;
}
.destroyer {
border: 1px solid blue;
width: 30%;
height: 30%;
display: flex;
flex-direction: row;
}
.destroyerSquare {
border: 1px solid orange;
width: 33%;
height: 100%;
}
<h1>BattleShip!</h1>
<p id="messageBoard">Place Your Ships!</p>
</div>
<div id="shipContainer" draggable="true">
<div class='destroyer' id='destroyer1'>
<div class='destroyerSquare'></div>
<div class='destroyerSquare'></div>
<div class='destroyerSquare'></div>
</div>
<div class='destroyer' id='destroyer2'>
<div class='destroyerSquare'></div>
<div class='destroyerSquare'></div>
<div class='destroyerSquare'></div>
</div>
<div class="battleship"></div>
<div class="cruiser"></div>
<div class="spyShip"></div>
</div>
<div id="wrapper">
</div>
I am trying to create a layout which allows you to resize the sidebar by dragging one edge of it. This behavior can be seen in CodePen/CodeSandbox, etc.. - you can drag each 'code window' to resize it. I am looking for this same behavior but with the page layout.
What I have come up with allows me to drag to resize, but if there is a lot of content within the 'main' area (area that is not the sidebar) it throws off the drag.
I want to be able to drag all the way to the edge of the screen, regardless of the content within.
I think the best way to show this issue is by a demo:
Original Demo:
const resizer = document.querySelector("#resizer");
const sidebar = document.querySelector("#sidebar");
resizer.addEventListener("mousedown", (event) => {
document.addEventListener("mousemove", resize, false);
document.addEventListener("mouseup", () => {
document.removeEventListener("mousemove", resize, false);
}, false);
});
function resize(e) {
const size = `${e.x}px`;
sidebar.style.width = size;
}
/**
* Helpers
*/
sidebar.style.width = '325px';
const mainContent = document.querySelector("#main-content");
function addContent() {
const mainContentStr = [...Array(10).keys()].map(i => "Main Content");
mainContent.innerHTML += mainContentStr.join(' ') + '<br /><br /><h1>Now drag to see how difficult it is, remove content to see how easy it is</h1>';
}
function removeContent() {
mainContent.innerHTML = '';
}
document.querySelector("#add-content")
.addEventListener('click', () => addContent())
document.querySelector("#remove-content")
.addEventListener('click', () => removeContent())
body {
position: relative;
height: auto;
min-height: 100vh;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
overflow: hidden;
margin: 0;
}
#wrapper {
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
flex-direction: column;
overflow: hidden;
position: absolute;
height: 100%;
width: 100%;
display: flex;
margin: 0;
padding: 0;
}
#container {
width: 100%;
height: 100%;
flex-shrink: 0;
position: relative;
display: flex;
overflow: hidden;
margin: 0;
padding: 0;
box-sizing: border-box;
}
#sidebar {
height: 100%;
position: relative;
margin 0;
padding: 0;
box-sizing: border-box;
background: lightgray;
border: 2px solid darkgray;
}
#resizer {
position: relative;
z-index: 2;
width: 18px;
cursor: col-resize;
border-left: 1px solid rgba(255, 255, 255, 0.05);
border-right: 1px solid rgba(0, 0, 0, 0.4);
background: #333642;
margin: 0;
padding: 0;
box-sizing: border-box;
}
#main {
background: lightblue;
height: 100%;
flex-grow: 1;
flex-direction: row;
position: relative;
display: flex;
margin: 0;
padding: 0;
}
#add-content {
width: 80px;
float: right;
background-color: forestgreen;
}
#remove-content {
width: 80px;
float: right;
background-color: salmon;
}
<div id="wrapper">
<div id="container">
<div id="sidebar">
<p>Sidebar content</p>
<button id="add-content">Add Content</button>
<button id="remove-content">Remove Content</button>
</div>
<div id="resizer"></div>
<div id="main">
<p id="main-content"></p>
</div>
</div>
</div>
Updated Demo:
After adding buttons, they appear stretched vertically 100%
const resizer = document.querySelector("#resizer");
const sidebar = document.querySelector("#sidebar");
resizer.addEventListener("mousedown", (event) => {
document.addEventListener("mousemove", resize, false);
document.addEventListener("mouseup", () => {
document.removeEventListener("mousemove", resize, false);
}, false);
});
function resize(e) {
const size = `${e.x}px`;
sidebar.style.flexBasis = size;
}
/**
* Helpers
*/
sidebar.style.flexBasis = '325px';
const mainContent = document.querySelector("#main-content");
function addContent() {
const mainContentStr = [...Array(10).keys()].map(i => "Main Content");
mainContent.innerHTML += mainContentStr.join(' ') + '<br /><br /><h1>Now drag to see how difficult it is, remove content to see how easy it is</h1>';
}
function removeContent() {
mainContent.innerHTML = '';
}
document.querySelector("#add-content")
.addEventListener('click', () => addContent())
document.querySelector("#remove-content")
.addEventListener('click', () => removeContent())
body {
position: relative;
height: auto;
min-height: 100vh;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
overflow: hidden;
margin: 0;
}
#wrapper {
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
flex-direction: column;
overflow: hidden;
position: absolute;
height: 100%;
width: 100%;
display: flex;
margin: 0;
padding: 0;
}
#container {
width: 100%;
height: 100%;
flex-shrink: 0;
position: relative;
display: flex;
overflow: hidden;
margin: 0;
padding: 0;
box-sizing: border-box;
}
#sidebar {
height: 100%;
position: relative;
margin 0;
padding: 0;
box-sizing: border-box;
background: lightgray;
border: 2px solid darkgray;
min-width: 0;
}
#resizer {
flex-basis: 18px;
position: relative;
z-index: 2;
cursor: col-resize;
border-left: 1px solid rgba(255, 255, 255, 0.05);
border-right: 1px solid rgba(0, 0, 0, 0.4);
background: #333642;
margin: 0;
padding: 0;
box-sizing: border-box;
}
#main {
flex-basis: 0;
flex-grow: 1;
min-width: 0;
background: lightblue;
height: 100%;
flex-direction: row;
position: relative;
display: flex;
margin: 0;
padding: 0;
}
#add-content {
width: 80px;
float: right;
background-color: forestgreen;
}
#remove-content {
width: 80px;
float: right;
background-color: salmon;
}
<div id="wrapper">
<div id="container">
<div id="sidebar">
<p>Sidebar content</p>
</div>
<div id="resizer"></div>
<div id="main">
<button id="add-content">Add Content</button>
<button id="remove-content">Remove Content</button>
<p id="main-content"></p>
</div>
</div>
</div>
To set a fixed invariable width in Flexbox, use flex-basis instead of width. From that fixed size, a flex item can then shrink or grow depending on the available space and the properties of flex-grow and flex-shrink.
Furthermore, the default min-width value of a flex item is auto. This means that the item cannot have a width smaller than its content size, even when you set its flex-basis to 0px. This means that we have to override the default min-width value to 0px so that upon dragging the #resizer element, it can shrink itself completely.
Here's a working example. I merely tweaked your width property to flex-basis in both JS and CSS. And then, I also added a min-width property of 0px to both #main and #sidebar.
const resizer = document.querySelector("#resizer");
const sidebar = document.querySelector("#sidebar");
resizer.addEventListener("mousedown", (event) => {
document.addEventListener("mousemove", resize, false);
document.addEventListener("mouseup", () => {
document.removeEventListener("mousemove", resize, false);
}, false);
});
function resize(e) {
const size = `${e.x}px`;
sidebar.style.flexBasis = size;
}
/**
* Helpers
*/
sidebar.style.flexBasis = '325px';
const mainContent = document.querySelector("#main-content");
function addContent() {
const mainContentStr = [...Array(10).keys()].map(i => "Main Content");
mainContent.innerHTML += mainContentStr.join(' ') + '<br /><br /><h1>Now drag to see how difficult it is, remove content to see how easy it is</h1>';
}
function removeContent() {
mainContent.innerHTML = '';
}
document.querySelector("#add-content")
.addEventListener('click', () => addContent())
document.querySelector("#remove-content")
.addEventListener('click', () => removeContent())
body {
position: relative;
height: auto;
min-height: 100vh;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
overflow: hidden;
margin: 0;
}
#wrapper {
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
flex-direction: column;
overflow: hidden;
position: absolute;
height: 100%;
width: 100%;
display: flex;
margin: 0;
padding: 0;
}
#container {
width: 100%;
height: 100%;
flex-shrink: 0;
position: relative;
display: flex;
overflow: hidden;
margin: 0;
padding: 0;
box-sizing: border-box;
}
#sidebar {
height: 100%;
position: relative;
margin 0;
padding: 0;
box-sizing: border-box;
background: lightgray;
border: 2px solid darkgray;
min-width: 0;
}
#resizer {
flex-basis: 18px;
position: relative;
z-index: 2;
cursor: col-resize;
border-left: 1px solid rgba(255, 255, 255, 0.05);
border-right: 1px solid rgba(0, 0, 0, 0.4);
background: #333642;
margin: 0;
padding: 0;
box-sizing: border-box;
}
#main {
flex-basis: 0;
flex-grow: 1;
min-width: 0;
background: lightblue;
height: 100%;
flex-direction: row;
position: relative;
display: flex;
margin: 0;
padding: 0;
}
#add-content {
width: 80px;
float: right;
background-color: forestgreen;
}
#remove-content {
width: 80px;
float: right;
background-color: salmon;
}
<div id="wrapper">
<div id="container">
<div id="sidebar">
<p>Sidebar content</p>
<button id="add-content">Add Content</button>
<button id="remove-content">Remove Content</button>
</div>
<div id="resizer"></div>
<div id="main">
<p id="main-content"></p>
</div>
</div>
</div>