I have two containers which need to share their parent's height, but the second container is added dynamically on demand. There can be a lot of content in both containers so the opportunity to scroll must be given.
I have a working solution for a 50/50 share, but I wonder if it's possible to share the height dynamically.
.wrapper__container {
display: flex;
height: 100%;
max-width: 100%;
flex-wrap: wrap;
align-items: flex-start;
}
.inside__container {
flex: 0 0 100%;
max-width: 100%;
overflow-y: auto;
}
Part of the wrapper component render method:
render() {
const maxHeight = this.state.showDetails ? '50%' : '100%';
const minHeight = this.state.showDetails ? '50%' : '100%';
return (
<div className="wrapper__container">
<Config
itemsGreen={this.state.itemsGreen}
itemsRed={this.state.itemsRed}
changeItemCount={this.changeItemCount}
/>
<Container
itemCount={this.state.itemsGreen}
className="inside__container"
style={{
backgroundColor: 'green',
maxHeight,
minHeight
}}
onClick={this.handleClick}
/>
{this.state.showDetails && <Container
itemCount={this.state.itemsRed}
className="inside__container"
style={{
backgroundColor: 'tomato',
maxHeight,
minHeight
}}
/>}
</div>
)
}
I've setup a codepen, where you can change the count of items to test the behaviour. Click on the green container to show the red one.
At least it would be a good solution to limit the green container to a max-height 50% and let the red container take up the rest. If the green, for example, is only 20% the red can take 80%.
In a perfect world this should be possible without js calculations but if someone has an idea to calculate this (only react/vanilla).
Target browser is IE11.
Edit: Added a new Pen which is broken, but shows the desired flexible behaviour when there are only a few items.
Each time the outer container is rendered, you need to get the height of the container and divide it by two, then apply that number as the height of each of your internal divs. Like so (using jquery):
var $two = $('<div id="two"></div>');
var $three = $('<div id="three"></div>');
$('#container').append($two);
$('#container').append($three);
var h = $('#one').height();
console.log((h/2)-1)
if($('#two').height() < ((h/2)-1)) {
$('#three').height( ( h-$('#two').height() ) - 1 );
} else {
$('#two').height((h/2)-1);
$('#three').height((h/2)-1);
}
Related
How to adjust this one whenever I click "Create Invoice" it will render a spinner with "Creating invoice". However the height of the card is also changing. I want it to be in fixed position
Please check GIF
https://imgur.com/a/ymJSnpy
const Loading = () => {
return (
<div className="loading" style={divStyle}>
<h4>Creating Invoice
<Spinner size="15px" color="#6491c6"/></h4>
</div>
)}```
could you share what are you putting in loading class and divStyle ?
I think you should add height of 40 and center it vertically if it's not centred on one of those classes:
display: flex;
align-items: center;
height: 40px;
right now I have a page with a grid of articles and a absolute positioned footer. What I am trying to accomplish, is that the article grid has a dynamic amount of columns, based on your window height, I thought about calculating the distance between the filter bar (above the article grid) and the footer and divide it by each of the height of a article row, but I just can't figure out how to do it.
Does anyone have an idea?
Code:
<FilterBar>
<div role="button" onClick={filterArticles} className="work-filter-container">
<input type="checkbox" className={`${checkedFilter ? 'checked' : ''} work-filter`} />
<p>ALLEEN WERK </p>
</div>
<div>
<p>sorteer op</p>
<button
type="button"
id="buttonrecent"
className={activeRecent ? 'active' : ''}
onClick={orderRecent}
>
recent
</button>
<span>/</span>
<button
type="button"
id="buttona-z"
onClick={orderAlphabetical}
className={activeAlphabetical ? 'active' : ''}
>
A - Z
</button>
</div>
</FilterBar>
<div>
<GridWrapper>
{articlesOrder &&
articlesOrder.map(article => {
const data = article.node;
const date = data._meta?.firstPublicationDate;
const formattedDate = dateTimeService.getDate({ dateTime: date });
return (
<Article key={data._meta.id}>
<Link href={`/articles/${data._meta.uid}`}>
<a>
<span>{formattedDate}</span>
<p>{data.title?.[0]?.text}</p>
</a>
</Link>
</Article>
);
})}
<br />
</GridWrapper>
</div>
<Footer position="absolute" textColor="white" />
CSS:
export const GridWrapper = styled.div`
display: flex;
flex-direction: column;
gap: 1.2rem;
width: fit-content;
padding: 0 2.3rem;
#media (${({ theme }) => theme.respondTo.desktop}) {
width: 100vw;
overflow-x: auto;
white-space: nowrap;
display: grid;
grid-auto-flow: column;
grid-template-rows: repeat(min(5), 1fr);
}
&::-webkit-scrollbar {
display: none;
}
`;
Screenshot of the problem below:
I want the result to be that the columns go till the footer, without having a fixed amount, like a dynamic amount based on the height of the window.
What you can do to solve this problem
First you have to find out the window.innerHeight where one column fits right, then you increase the screen height with your inspect elements, set it to responsive and look at which height two columns fit right, for example if one column fits the best at 500px window.innerHeight and two columns at 530px, then you know every 30px that is added to your innerHeight, the column count has to increase by 1.
First you have to use the React useState to keep track of the column count
const [columnsAmount, setColumnsAmount] = useState();
With all the above information, you can create a for loop that will look similar to this:
useEffect(() => {
let columns = 1;
for (let i = 500; i < window.innerHeight; i += 30) {
columns += 1;
}
setColumnsAmount(columns);
}, []);
I have a container div that holds a react handsontable component, and I want to use the autosizing of the component but at the same time have it centered in the screen (or an outer div).
So in this example:
https://jsfiddle.net/opike99/b1ux0rLy/5/
I'm trying to get the width of div #example1 to match the contents of the table (so by changing the number of columns, the div width will adjust accordingly).
HTML:
<script src="https://cdn.jsdelivr.net/npm/handsontable#11.1/dist/handsontable.full.min.js"></script>
<link type="text/css" rel="stylesheet" href="https://cdn.jsdelivr.net/npm/handsontable#11.1/dist/handsontable.full.min.css" />
<script src="https://handsontable.com/docs/8.3.2/components/numbro/dist/languages.min.js"></script>
<div class="outer2">
<div class="outer1">
<div id="example1">
</div>
</div>
</div>
JS:
const container = document.querySelector('#example1');
const numberOfColumns = 7;
const hot = new Handsontable(container, {
data: Handsontable.helper.createSpreadsheetData(5, numberOfColumns),
colHeaders: true,
rowHeaders: true,
hiddenColumns: true,
width: 'auto',
height: 'auto',
licenseKey: 'non-commercial-and-evaluation',
});
// re-render your Handsontable instance
hot.render()
CSS:
.outer2 {
}
.outer1 {
}
#example1 {
border-style: solid;
/* width: fit-content; */
}
So I've been playing around with your example, and got the following results:
There's actually three tings you need to do:
The generated $('.wtHolder') has a width: 680px defined on a style attribute, so the only way to remove it is programatically.
$('.ht_master.handsontable, #example1') need width: fit-content
Using a flexbox, I was able to centre the table. I set display: flex; justify-content: center; on $('.outer1').
And for some reason, the order in which these are applied is important too. I got it working with a setTimeout, although you'd probably want something more sophisticated.
setTimeout(function() {
document.querySelector('.wtHolder').style.width = 'initial';
document.querySelector('#example1').style.width = 'fit-content';
const outer = document.querySelector('.outer1');
outer.style.display = 'flex';
outer.style.justifyContent = 'center';
}, 2000);
Let me know how you go.
I just started to use ReactJS. I currently want to change my Navbar color when user scroll to different section. For example, my section one is red and section 2 is green then my section 3 is blue. I want to let the Nav know that once User enter/scroll to section 1 and it will change color to make the color red and for section 2 and section 3 as well.
Right now I used the window.scroll to achieve this function.
const changeBackground = () => {
if(window.scrollY >= 898 && window.scrollY <= 1997){
//section = '1'
setColor('red')
}
else if(window.scrollY >= 1998 && window.scrollY <= 3097) {
//section = '2'
setColor('green')
}
else if(window.scrollY >= 3098) {
//section = '3'
setColor('blue')
}
My Current problem is that my height is fixed so section 1 is between 898 and 1997px.
However I want to set the height to 100vh so that each section fill up the screen, and based the the 100vh, the px will be different depends on the user screen size.
Any thoughts/tips to let the nav know which section it is on right now?
Thanks so much! happy coding.
One possible solution could be by using intersectional observers. They allow us to observe when an element is visible. We can set a threshold which would make sure that it only triggers when given ratio is visible.
You can use the react-intersection-observer hook to check if each section is in view, once they are you can use that state to change navigation bar color.
You can test this out in the following sandbox:
https://codesandbox.io/s/competent-rubin-nhqz6
This code is not production ready, but you should be able to get an idea of how we can use the intersection observer.
import "./styles.css";
import React from "react";
import { useInView } from "react-intersection-observer";
export default function App() {
const [section1Ref, section1InView] = useInView({ threshold: 0.5 });
const [section2Ref, section2InView] = useInView({ threshold: 0.5 });
return (
<div className="App">
<nav
className="NavBar"
style={{
backgroundColor: section1InView
? "red"
: section2InView
? "blue"
: "green"
}}
/>
<div className="Container">
<section className="Section" ref={section1Ref}>
Section 1
</section>
<section className="Section" ref={section2Ref}>
Section 2
</section>
<section className="Section">Section</section>
</div>
</div>
);
}
Style sheet is simply setting the height to be 100vh minus the header height. And it's ensuring that the scroll works as expeted.
.NavBar {
width: 100%;
height: 20px;
background-color: red;
}
.Container {
height: calc(100vh - 20px);
overflow-y: scroll;
}
.Section {
height: calc(100vh - 20px);
border-bottom: 2px solid black;
}
I'm trying to create with React.js a type of scroll like this one: http://spassky-fischer.fr/, where two divs are scrolling in inverse directions. They are using transform: translateY(), and I tried to implement it as well but I don't get where I'm wrong here. Here's the architecture of the projet. The current version is also here: http://noiseless-tendency.surge.sh/
App.js:
ComponentDidMount(){
window.addEventListener("scroll", this.scrollHandler);
}
...
scrollHandler = () => {
this.setState({
scrollPositionY: window.scrollY
})
}
...
render() {
return (
<div className="App">
<MainItemsContainer {...this.state} />
</div>
);
}
MainItemsContainer.js:
render() {
let style_first = {
transform: `translateY(${this.props.scrollPositionY})`,
overflow: "hidden"
}
let style_second = {
transform: `translateY(-${this.props.scrollPositionY})`,
overflow: "hidden"
}
return (
<div className="main_items_container">
<section
style={style_first}
className="main_items_container_child">
<ItemsContainer {...this.props}/>
</section>
<section
style={style_second}
className="main_items_container_child">
<ItemsContainer {...this.props}/>
</section>
</div>
);
}
App.css:
.main_items_container {
width: 100vw;
display: flex;
align-items: center;
justify-content: center;
position: fixed;
}
.main_items_container .main_items_container_child{
width: 50%;
height: 100vh;
overflow: scroll;
}
The sample site you linked actually uses the wheel event rather than the scroll event. It looks like they use this library to accomplish it: https://swiperjs.com/demos/ . My understanding is that the scroll event only fires if there's a scrollbar, which is why your event handler didn't fire.
I've created a Code Sandbox that produces the effect you want in React. It does rely on jQuery to compute the height of the whole element, and to set the initial transformation for the left half. However, those are just convenience methods, and if you don't want jQuery as a dependency, you can find workarounds for those pretty easily.
So you could use hooks and pass a custom css var through inline styling on state change to update your translateY. I have not tested but I hope you get my drift.
let elRef = useRef(null)
let[ height, setHeight] = useState()
use useLayoutEffect hook to add the event listener
useLayoutEffect (()=>{
if(!elRef) return
elRef.current.addEventListener("scroll", setHeight(elRef.current.scrollY));
return elRef.current.removeEventListener("scroll", setHeight());
}, )
and put the ref on you outermost div perhaps , so your outer div would look like
<div className='container' ref={elRef} style{{ --height: height}} >
<div className='columOne' > </div>
<div className='columTwo' > </div>
</div>
in your css (I haven't put all that is required but just showing how you custom css var is used
.container{
display: flex;
flex-direction: row
}
And within that equal sized columns
.columnOne{
transform: `translateY(calc(var(--height) * 1px)`,
overflow: "hidden"
}
.columnTwo{
transform: `translateY(-calc(var(--height) * 1px)`,
overflow: "hidden"
}
Does that help. Let me know if I could be more clear. Or use styled components and pass a prop in to achieve the same result.