Applying CSS parameters based on scroll position with JavaScript - javascript

In the example below, I have two invisible buttons that fill the whole page. The button in the second half horizontally scrolls to the next section, and the button on left to the previous section.
const createButton = () => document.createElement("button")
const insertButton = button => {
document.body.append(button)
return button
}
const [goToPreviousSection, goToNextSection] = [
createButton(),
createButton()
].map(insertButton)
goToPreviousSection.addEventListener("click", () => {
window.scrollBy(-window.innerWidth, 0)
})
goToNextSection.addEventListener("click", () => {
window.scrollBy(window.innerWidth, 0)
})
* {
margin: 0;
padding: 0
}
html { height: 100% }
html,
body,
section {
display: flex;
flex-grow: 1
}
section {
flex: 1 0 100%;
justify-content: center;
align-items: center
}
section:nth-of-type(1) { background: orange }
section:nth-of-type(2) { background: limeGreen }
section:nth-of-type(3) { background: royalBlue }
h2 {
color: white
}
button {
background: transparent;
position: fixed;
top: 0;
width: 50%;
height: 100%;
border: none
}
button:nth-of-type(1) {
left: 0;
cursor: w-resize
}
button:nth-of-type(2) {
right: 0;
cursor: e-resize
}
<section><h2>1</h2></section>
<section><h2>2</h2></section>
<section><h2>3</h2></section>
How can I set the width of the second button to be 100% and z-index to 1 when it's at 0 page scroll position on the left, and same for the width of the first button when it's scrolled to the end of the page?

Here is an approach that works by toggling a class on both buttons to show them fullscreen when we reach one side or the other. It is important to increase the z-index of the fullscreen button since the left button is rendered before the next button.
const createButton = () => document.createElement("button")
const insertButton = button => {
document.body.append(button)
return button
}
const [goToPreviousSection, goToNextSection] = [
createButton(),
createButton()
].map(insertButton)
const previousButtonFullscreen = () => {
goToNextSection.classList.remove("fullscreen")
goToPreviousSection.classList.add("fullscreen")
}
const nextButtonFullscreen = () => {
goToPreviousSection.classList.remove("fullscreen")
goToNextSection.classList.add("fullscreen")
}
const noButtonFullscreen = () => {
goToPreviousSection.classList.remove("fullscreen")
goToNextSection.classList.remove("fullscreen")
}
const updateButtons = () => {
if (window.scrollX === 0) {
nextButtonFullscreen()
} else if (document.body.scrollWidth - window.scrollX === window.innerWidth) {
previousButtonFullscreen()
} else {
noButtonFullscreen()
}
}
goToPreviousSection.addEventListener("click", () => {
window.scrollBy(-window.innerWidth, 0)
updateButtons();
})
goToNextSection.addEventListener("click", () => {
window.scrollBy(window.innerWidth, 0)
updateButtons()
})
updateButtons()
* {
margin: 0;
padding: 0
}
html { height: 100% }
html,
body,
section {
display: flex;
flex-grow: 1
}
section {
flex: 1 0 100%;
justify-content: center;
align-items: center
}
section:nth-of-type(1) { background: orange }
section:nth-of-type(2) { background: limeGreen }
section:nth-of-type(3) { background: royalBlue }
h2 {
color: white
}
button {
background: transparent;
position: fixed;
top: 0;
width: 50%;
height: 100%;
border: none
}
button:nth-of-type(1) {
left: 0;
cursor: w-resize
}
button:nth-of-type(2) {
right: 0;
cursor: e-resize
}
.fullscreen {
width: 100%;
z-index: 10;
}
<section><h2>1</h2></section>
<section><h2>2</h2></section>
<section><h2>3</h2></section>

Related

how can I scroll page to the specific position

I would like to ask why my page goes up when I clicked it again? I mean if I click on the 'projects' for example then it goes to the projects section which is (0, 590), but If I click it on again or click on skills then it goes up to the top of the page.
const home_view = document.querySelector('.home');
const project_view = document.querySelector('.project');
const skill_view = document.querySelector('.skill');
const about_view = document.querySelector('.about');
const hire_view = document.querySelector('.hire');
home_view.addEventListener('click', () => {
window.scrollTo(0, 0);
});
project_view.addEventListener('click', () => {
window.scrollTo(0, 590);
});
skill_view.addEventListener('click', () => {
window.scrollTo(0, 1250);
});
about_view.addEventListener('click', () => {
window.scrollTo(0, 1750);
});
hire_view.addEventListener('click', () => {
window.scrollTo(0, 2350);
});
Generally, if you want to scroll to specific element, it would be better to use scrollIntoView function
Ex:
const projectElement = document.querySelector('project-element-selector')
project_view.addEventListener('click', () => {
projectElement.scrollIntoView({ behavior: "smooth" });
});
Because using scrollTo for this purpose may not achieve the same result in different screens width.
I didn't add every css part, because I guess it's not necessary in this case.
I don'k know that this added HTML will give you more help, but I hope so
const home_view = document.querySelector('.home');
const project_view = document.querySelector('.project');
const skill_view = document.querySelector('.skill');
const about_view = document.querySelector('.about');
const hire_view = document.querySelector('.hire');
home_view.addEventListener('click', () => {
window.scrollTo(0, 0);
});
project_view.addEventListener('click', () => {
window.scrollTo(0, 590);
});
skill_view.addEventListener('click', () => {
window.scrollTo(0, 1250);
});
about_view.addEventListener('click', () => {
window.scrollTo(0, 1750);
});
hire_view.addEventListener('click', () => {
window.scrollTo(0, 2350);
});
*,
*::before,
*::after {
padding: 0;
margin: 0;
box-sizing: border-box;
text-decoration: none;
list-style: none;
border: none;
outline: none;
}
.nav_container {
height: 200vh;
top: 0;
left: 0;
margin: 0 auto;
background-color: rgba(13, 12, 14, 0.8);
border-bottom: var(--nav-line) solid var(--nav-borderline-clr);
}
.main_nav {
display: flex;
justify-content: space-between;
align-items: center;
padding: 2rem;
}
.main_nav a {
color: var(--nav-text-clr);
font-weight: 400;
transition: .3s;
}
.main_nav a:hover {
color: var(--white-clr);
}
.nav_list {
display: flex;
gap: 2.5rem;
text-transform: uppercase;
}
.nav_list-item {
position: relative;
}
.nav_list-item:after{
content: '';
position: absolute;
left: 0;
bottom: -33px;
width: 0;
height: var(--nav-line);
background-color: var(--btn-border-clr);
transition: .3s;
border-radius: 2px;
box-shadow: rgba(219, 94, 44, .6) 0px 0px 10px;
}
.nav_list-item:hover:after {
width: 100%;
}
<header class="nav_container">
<nav class="main_nav">
<ul class="nav_list">
<li class="nav_list-item active home">Home</li>
<li class="nav_list-item project">Projects</li>
<li class="nav_list-item skill">Skills</li>
<li class="nav_list-item about">About Me</li>
</ul>
<button class="btn hire" aria-label="button">Hire Me</button></a>
</nav>
</header>

How do I change grid for a memory game using dropdown list, I've manage to make it work but the cards stops flipping when I change the grid?

When I first load page the game works but when I change grid the game cards don't flip. I'm not sure if it the use of onchange inside the select tag or it something else. If I change the value of a variable named value inside displayCardsDiv manual it also works fine maybe if I could find a way to update it by dropddown list or button click it will work.
Html
<div class="game-container" >
<script>displayCardsDiv();</script>
<div ></div>
</div>
</div>
<div class="game-title">
<label class="changeGrid">change Grid</label>
<select id="grid" name="grid" onchange="displayCardsDiv()">
<option value="first" id="first">2x2</option>
<option value="second" id="second">3x2</option>
<option value="third" id="third">4x3</option>
</select>
<button class="reset-btn" onclick="resetGame()">Reset</button>
</div>
<script src="./src/script.js"></script>
</body>
Javascript
"src/img/apple-eye.png",
"src/img/apple-eye.png",
"src/img/blue-nife.png",
"src/img/blue-nife.png",
"src/img/devil.png",
"src/img/devil.png",
"src/img/headless.png",
"src/img/headless.png",
"src/img/heart.png",
"src/img/heart.png",
"src/img/mommy.png",
"src/img/mommy.png",
];
class MemoryGame {
constructor() {
this.cardsArray = playCard;
}
beforeGameStart() {
this.cardChecker = null;
this.matchingCardsArray = [];
this.isLocked = true;
setTimeout(() => {
this.shuffleCards(this.cardsArray);
this.isLocked = false;
}, 500);
}
handleCardFlip(card) {
if (this.flipCard(card)) {
card.classList.add("showingCard");
if (this.cardChecker) {
this.checkForMatch(card);
} else {
this.cardChecker = card;
}
}
}
checkForMatch(card) {
if (this.findTypeOfCard(card) === this.findTypeOfCard(this.cardChecker))
this.matchCards(card, this.cardChecker);
else this.misMatchCards(card, this.cardChecker);
this.cardChecker = null;
}
matchCards(firstCard, secondCard) {
this.matchingCardsArray.push(firstCard);
this.matchingCardsArray.push(secondCard);
firstCard.classList.add("matched");
secondCard.classList.add("matched");
setTimeout(() => {
if (this.matchingCardsArray.length === this.cardsArray.length) {
alert("All cards matched");
resetGame();
}
}, 1000);
}
misMatchCards(firstCard, secondCard) {
this.isLocked = true;
setTimeout(() => {
firstCard.classList.remove("showingCard");
secondCard.classList.remove("showingCard");
this.isLocked = false;
}, 1000);
}
shuffleCards(cardsArray) {
cardsArray.forEach((card) => {
let randomPos = Math.floor(Math.random() * cardsArray.length);
card.style.order = randomPos;
});
}
findTypeOfCard(card) {
return card.getElementsByClassName("value")[0].src;
}
flipCard(card) {
return (
!this.isLocked &&
!this.matchingCardsArray.includes(card) &&
card !== this.cardChecker
);
}
}
function resetGame() {
location.reload();
}
let gameContainer = document.querySelector(".game-container");
function twoByTwoGrid() {
gameContainer.style.gridTemplateColumns = "repeat(2, auto)";
return imagesArray.slice(0, 4);
}
function threeByTwoGrid() {
gameContainer.style.gridTemplateColumns = "repeat(3, auto)";
return imagesArray.slice(0, 6);
}
function displayCardsDiv() {
let deckOfCards = [];
let displayGameCards = "";
let value = document.querySelector("#grid").value;
if (value == "first") {
deckOfCards = twoByTwoGrid();
}
if (value === "second") {
deckOfCards = threeByTwoGrid();
}
if (value !== "first" && value !== "second") {
gameContainer.style.gridTemplateColumns = "repeat(4, auto)";
deckOfCards = [...imagesArray];
}
for (let i in deckOfCards) {
displayGameCards += `<div class="card">
<div class="card-back card-face"><img class="demonsCards" src="src/img/demons.png"></div>
<div class="card-front card-face"><img class="value" src="${deckOfCards[i]}"></div>
</div>`;
}
document.getElementsByClassName("game-container")[0].innerHTML =
displayGameCards;
}
displayCardsDiv();
const playCard = document.querySelectorAll(".card");
const game = new MemoryGame(playCard);
game.beforeGameStart();
for (let i = 0; i < imagesArray.length; i++) {
playCard[i].addEventListener("click", () => game.handleCardFlip(playCard[i]));
}
module.exports = { game };
CSS
margin: 0;
padding: 0;
box-sizing: border-box;
}
html {
min-height: 100vh;
}
body {
margin: 0;
background: radial-gradient(#46bddb, #4672db);
}
h1{
background: -webkit-repeating-linear-gradient(#eee, #333);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
img {
height: 175px;
width: 125px;
}
.game-title {
color: aliceblue;
font-family: 'Noto Sans Mono', monospace;
font-weight: normal;
text-align: center;
font-size: 4em;
margin-top: 0px;
}
.game-info-container {
grid-column: 1 / -1;
display: flex;
justify-content: space-between;
}
.game-info {
font-family: 'Pacifico', cursive;
color: aliceblue;
font-size: 4em;
}
.changeGrid{
font-size: large;
}
.game-container {
margin: 50px auto;
display: grid;
grid-template-columns:repeat(4, auto);
grid-gap: 10px;
justify-content: center;
perspective: 500px;
}
.card {
position: relative;
height: 175px;
width: 125px;
cursor: pointer;
}
.card-face {
position: absolute;
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
border-radius: 12px;
border-width: 1px;
border-style: solid;
overflow: hidden;
transition: transform 500ms ease-in-out;
backface-visibility: hidden;
}
.card.showingCard .card-back {
transform: rotateY(180deg);
}
.card.showingCard .card-front {
transform: rotateY(0);
}
.card-back {
background-color:aliceblue;
border-color: aliceblue;
transform: rotateY(0);
}
.demonsCards {
align-self: flex-start;
transition: transform 100ms ease-in-out;
transform: translateY(-10px);
}
.card:active {
transform: scale(0.79);
transition: transform .1s;
}
.card-front:hover .card-value {
transform: scale(1);
}
.card-front {
background-color: #FFBB89;
border-color: #333;
transform: rotateY(-180deg);
}
#media (max-width: 600px) {
.game-container {
grid-template-columns: repeat(2, auto)
}
.game-info-container {
flex-direction: column;
align-items: center;
}
}

Changing CSS parameters based on scroll position

In the example below, I have two invisible buttons – button in the right half, on click, horizontally scrolls to the next section, and the button in the left half to the previous section. Buttons show left and right arrow cursors when user hovers over them for displaying scroll direction.
I would like to toggle the cursor of goToPreviousSectionButton to default when scrollPosition === 0, and same for goToNextSectionButton when scrollPosition === maxScrollPosition.
To put it plainly: when you run the code snippet, hover your mouse cursor to the left of number 1. You can see that it’s a left arrow cursor now. I would like it to be a default cursor, since you can’t go left because you’re at the beginning. Same when you reach to the number 3, but this time for the right arrow, since you can’t go any further, so it’s pointless for the right arrow to be shown.
I’m having trouble getting this to work. Any help would be greatly appreciated.
let scrollPosition = 0
const maxScrollPosition = document.body.scrollWidth - window.innerWidth
const goToPreviousSectionButton = document.createElement("button")
const goToNextSectionButton = document.createElement("button")
document.body.appendChild(goToPreviousSectionButton)
document.body.appendChild(goToNextSectionButton)
if (scrollPosition === 0) {
// If scroll position is at the beginning
}
if (scrollPosition === maxScrollPosition) {
// If scroll position at the end
}
goToPreviousSectionButton.addEventListener("click", () => {
window.scrollBy(-window.innerWidth, 0)
})
goToNextSectionButton.addEventListener("click", () => {
window.scrollBy(window.innerWidth, 0)
})
* {
margin: 0;
padding: 0
}
html { height: 100% }
html, body, main {
display: flex;
flex-grow: 1
}
section {
display: grid;
place-items: center;
flex: 1 0 100%
}
section:nth-of-type(1) { background: orange }
section:nth-of-type(2) { background: limeGreen }
section:nth-of-type(3) { background: royalBlue }
h2 { color: white }
button {
background: transparent;
position: fixed;
top: 0;
width: 50%;
height: 100%;
border: none;
touch-action: manipulation;
-webkit-tap-highlight-color: transparent
}
:focus { outline: none }
button:nth-of-type(1) { /* Left button */
left: 0;
cursor: w-resize
}
button:nth-of-type(2) { /* Right button */
right: 0;
cursor: e-resize
}
<main>
<section>
<h2>1</h2>
</section>
<section>
<h2>2</h2>
</section>
<section>
<h2>3</h2>
</section>
</main>
One idea is to add extra elements using pseudo-element that you will cover your invisible buttons and disable the action on them:
const goToPreviousSectionButton = document.createElement("button")
const goToNextSectionButton = document.createElement("button")
document.body.appendChild(goToPreviousSectionButton)
document.body.appendChild(goToNextSectionButton)
goToPreviousSectionButton.addEventListener("click", () => {
window.scrollBy(-window.innerWidth, 0)
})
goToNextSectionButton.addEventListener("click", () => {
window.scrollBy(window.innerWidth, 0)
})
* {
margin: 0;
padding: 0
}
html,body { height: 100% }
body, main {
display: flex;
flex-grow: 1
}
section {
display: grid;
place-items: center;
flex: 1 0 100%
}
section:nth-of-type(1) { background: orange }
section:nth-of-type(2) { background: limeGreen }
section:nth-of-type(3) { background: royalBlue }
h2 { color: white }
button {
background: transparent;
position: fixed;
top: 0;
width: 50%;
height: 100%;
border: none;
touch-action: manipulation;
-webkit-tap-highlight-color: transparent
}
:focus { outline: none }
button:nth-of-type(1) { /* Left button */
left: 0;
cursor: w-resize
}
button:nth-of-type(2) { /* Right button */
right: 0;
cursor: e-resize
}
/* Added */
main:before,
main:after{
content:"";
z-index:9;
position:relative;
flex: 1 0 50%;
}
main:before {
margin-right:-50%;
}
main:after {
margin-left:-50%;
}
/**/
<main>
<section>
<h2>1</h2>
</section>
<section>
<h2>2</h2>
</section>
<section>
<h2>3</h2>
</section>
</main>
if (scrollPosition === 0) {
goToPreviousSectionButton.classList.add('default')
}
if (scrollPosition === maxScrollPosition) {
goToPreviousSectionButton.classList.add('default')
}
css:
.default {
cursor: default
}

How to adjust div height by dragging whole bottom border line instead of bottom right corner in react?

I have one react component. I am able to adjust the height by adding resize: vertical;
overflow: auto; in my css file. However, I only can adjust by dragging bottom right corner of the border. Is it possible to change it to whole bottom line? Or any other react api can achieve this?
This is an example of how I adjust the height by dragging bottom right corner.
This is my component.
<div class='map'>
<MyMapComponent
handleChange={this.handleChange}
handleSubmit={this.handleSubmit}
date ={this.state.date}
getMap={this.getMap}
updateStatus = {this.state.updateStatus}
filter={this.state.filter}
filterList={this.state.filterList}
inputProps={{
classes: {
input: classes.multilineColor
}
}}
>
{/*this.getMap()*/}
</MyMapComponent>
</div>
This is my css file.
.map{
border: 2px solid;
padding: 20px;
width: 300px;
resize: vertical;
overflow: auto;
}
I follow this horizontal resize panel example to create a vertical one.
This is my edited resize panel
import React from "react"
import ReactDOM from "react-dom";
import './ResizablePanels.css';
class ResizablePanels extends React.Component {
eventHandler = null
constructor () {
super()
this.state = {
isDragging: false,
panels: [800, 300, 0]
}
}
componentDidMount () {
ReactDOM.findDOMNode(this).addEventListener('mousemove', this.resizePanel)
ReactDOM.findDOMNode(this).addEventListener('mouseup', this.stopResize)
ReactDOM.findDOMNode(this).addEventListener('mouseleave', this.stopResize)
}
startResize = (event, index) => {
this.setState({
isDragging: true,
currentPanel: index,
initialPos: event.clientY
})
}
stopResize = () => {
if (this.state.isDragging) {
console.log(this.state)
this.setState(({panels, currentPanel, delta}) => ({
isDragging: false,
panels: {
...panels,
[currentPanel]: (panels[currentPanel] || 0) - delta,
[currentPanel - 1]: (panels[currentPanel - 1] || 0) + delta
},
delta: 0,
currentPanel: null
}))
console.log(this.state)
}
}
resizePanel = (event) => {
if (this.state.isDragging) {
//console.log(event.clientY +" "+this.state.initialPos);
const delta = event.clientY - this.state.initialPos
this.setState({
delta: delta
})
}
}
render() {
const rest = this.props.children.slice(1);
// console.log(this.props);
return (
<div className="panel-container" onMouseUp={() => this.stopResize()}>
<div className="panel" style={{height: this.state.panels[0]}}>
{this.props.children[0]}
</div>
{[].concat(...rest.map((child, i) => {
return [
<div onMouseDown={(e) => this.startResize(e, i + 1)}
key={"resizer_" + i}
style={this.state.currentPanel === i+1 ? {top: this.state.delta} : {}}
className="resizer"></div>,
<div key={"panel_" + i} className="panel" style={{height: this.state.panels[i + 1]}}>
{child}
</div>
]
}))}
</div>
)
}
}
export default ResizablePanels;
and this is my css file for this panel
#import url('https://fonts.googleapis.com/css?family=Ubuntu');
html {
background: #333;
font-family: sans-serif;
}
h1 {
color: white;
}
.panel-container {
display: flex;
min-height: 100%;
justify-content: center;
flex-direction: column;
text-align: center;
}
.panel {
background: #EEE;
border: 0px solid gray;
padding: 1px;
}
.panel:first-child {
}
.resizer {
height: 8px;
background: darkGray;
position: relative;
cursor: row-resize;
flex-shrink: 0;
-webkit-user-select: none; /* Chrome all / Safari all */
-moz-user-select: none; /* Firefox all */
-ms-user-select: none; /* IE 10+ */
user-select: none; /* Likely future */
}
.resizer::after,
.resizer::before {
content: "";
border-left: 1px solid #333;
position: absolute;
top: 50%;
transform: translateX(-100%);
right: 0;
display: inline-block;
height: 20px;
margin: 0 2px;
}
.resizer::before {
top: 0;
}

Make overlay menu slide from top down

I'm creating a navigation for the site I'm building that currently slides in as an overlay from the left. What I'm trying to do, though, is get it to slide in from the top.
Below is the current CSS and JS for the menu specifically. I feel like it's simple to rotate where the menu comes in from, but I just can't figure it out.
CSS
.sidenav {
height: 100%;
width: 0;
position: fixed;
z-index: 10;
background-color: rgba(0,162,85,.9);
overflow-x: hidden;
transition: 0.5s;
padding-top: 60px;
text-align: center;
}
.sidenav a {
padding: 8px 8px 8px 32px;
text-decoration: none;
font-size: 25px;
color: #f1f1f1;
display: block;
transition: 0.3s;
}
.sidenav a:hover {
color: lightgray;
opacity: 1;
}
.sidenav .closebtn {
position: absolute;
top: 355px;
right: 25px;
font-size: 36px;
margin-left: 50px;
}
JS
var menuItems = [
{
name: "HowToQuit",
openFunction: "openHow()",
closeFunction: "closeHow()",
state: false //closed
},
{
name: "StayingQuit",
openFunction: "openStay()",
closeFunction: "closeStay()",
state: false
},
{
name: "FactsAndMyths",
openFunction: "openFacts()",
closeFunction: "closeFacts()",
state: false
}
];
function openHow() {
document.getElementById("howtoquitnav").style.width = "100%";
document.getElementById("howtoquitnav").style.maxWidth = "1046px";
}
function closeHow() {
document.getElementById("howtoquitnav").style.width = "0";
}
function openStay() {
document.getElementById("stayquit").style.width = "100%";
document.getElementById("stayquit").style.maxWidth = "1046px";
}
function closeStay() {
document.getElementById("stayquit").style.width = "0";
}
function openFacts() {
document.getElementById("factsmyths").style.width = "100%";
document.getElementById("factsmyths").style.maxWidth = "1046px";
}
function closeFacts() {
document.getElementById("factsmyths").style.width = "0";
}
function handleMenuItem(menuItemName) {
for (var i = 0; i < menuItems.length; i++) {
if (menuItems[i].name === menuItemName && !menuItems[i].state) {
var open = new Function(menuItems[i].openFunction);
open();
menuItems[i].state = true;
} else {
var close = new Function(menuItems[i].closeFunction);
close();
menuItems[i].state = false;
}
}
}

Categories

Resources