I am creating a web application for my react-native application. I feel quite comfortable in styling on react-native and was trying to use flexbox on the web also hoping it would allow me to use my react-native knowledge. But the styles behave a little differently on the web and I am having a hard time finding a good resource that explains the basics. I understand the meaning of each flexbox properly but there is a gap in my understanding due to which I am not able to achieve the desired layout.
Please refer to the following code snippet. Link to code sandbox also below the snippet.
import React, { useState } from "react";
import ReactDOM from 'react-dom';
import { Box, Header, Text, Avatar, Menu, List } from "grommet";
import { MoreVertical } from "grommet-icons";
const AlarmDetailsHeader = () => {
return (
<Header className="alarmDetailsHeader" background="brand" pad="small">
<Text>"alarm1"</Text>
<Menu icon={<MoreVertical />} items={[{ label: "logout" }]} />
</Header>
);
};
const AlarmDetails = (props) => {
return (
<Box className="alarmDetails" flex={true}>
<AlarmDetailsHeader />
<Box flex={true} />
</Box>
);
};
const AlarmSummary = (item, index, state) => {
return (
<Box margin="medium">
<Text>{item.name}</Text>
</Box>
);
};
const AlarmListHeader = (props) => (
<Header className="alarmListHeader" background="brand" pad="small" border="right">
<Avatar src="//s.gravatar.com/avatar/b7fb138d53ba0f573212ccce38a7c43b?s=80" />
<Text level={5}>"Alarms</Text>
<Menu
icon={<MoreVertical />}
items={[
{ label: "First Action", onClick: () => {} },
{ label: "Second Action", onClick: () => {} }
]}
/>
</Header>
);
const AlarmList = () => {
const [alarms, setAlarms] = useState([
{
name: "alarm1"
},
{
name: "alarm2"
}
]);
return (
<Box className="alarmList" fill="vertical">
<AlarmListHeader />
{/* <List data={alarms} children={AlarmSummary} /> */}
</Box>
);
};
const App = () => {
return (
<Box className="alarmListWithDetails" direction="row" flex={true}>
<AlarmList />
<AlarmDetails />
</Box>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
rootElement
);
.App {
font-family: sans-serif;
text-align: center;
}
.routerContainer {
display: flex;
height: "100vh";
width: "100vw";
justify-content: center;
}
.alarmListWithDetails {
max-width: "1080px";
}
.alarmList {
background-color: ivory;
width: "320px";
}
.alarmDetails {
background-color: antiquewhite;
}
.alarmListHeader {
height: '80px'
}
.alarmDetailsHeader {
height: '80px'
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="theme-color" content="#000000">
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/grommet/2.16.2/grommet.min.js"></script>
<!--
manifest.json provides metadata used when your web app is added to the
homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title>
<style type="text/css">
body {
margin: 0;
}
#root {
height: 100vh;
width: 100vw;
background-color: lightblue;
}
</style>
</head>
<body>
<noscript>
You need to enable JavaScript to run this app.
</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>
https://codesandbox.io/s/alarm-web1-yztws?file=/src/styles.css
I am trying to achieve the below layout which is similar to the Whatsapp Web layout.
This is what I am getting at the moment:
I want to assign a max-width for the main window but that doesn't seem to take effect. I want the sidebar of the left to cover the full height of the window for which I tried using different CSS properties such as height: '100%' or fill: vertical or flex: 1 but that doesn't have any effect either.
Similarly, I want the details panel to take the complete height. I want the height of both the headers to be the same for which I specified height: 80px but that doesn't seem to have any effect either. These things work quite easily on mobile but for some reason, the web doesn't work the same.
I found flexboxfroggy.com and finished all the levels but as I mentioned, I understand the flexbox properties but the web requires some more things than just the flexbox properties to get the layout right.
Your CSS is causing some issues, but essentially you need to look at how parent and children selection works. You need to do a reset at the top level to allow 100% for child elements below it. The 100% should be working but it is set at the HTML/BODY level first. Similar with Flex, it needs to be set at a parent level before the children can display in the manner you set. Then you can use something like flex-direction: column; which will then create a whole column and then any div inside that you set to flex: 1 and you'll get a full height. You can read more here.
I wouldn't recommend using the VH or VW as they only fill the window in its current state. If that window changes then the selection will remain the previous dimension only.
An example from your CSS above is below, I've removed code that isn't working and added some.
html, body {
height: 100%;
}
body {
display: flex;
}
.App {
font-family: sans-serif;
text-align: center;
}
.routerContainer {
justify-content: center;
}
.alarmListWithDetails {
max-width: 1080px;
}
.alarmList {
background-color: ivory;
width: 320px;
}
.alarmDetails {
background-color: antiquewhite;
}
.alarmListHeader {
height: 80px;
}
.alarmDetailsHeader {
height: 80px;
}
Related
I have created a iFrame on my 3D website in which renders a path from my portfolio. I have been attempting to scroll or touch (mobile) this iFrame for a while now, the desktop version works fine, you can scroll, access pages, etc although on mobile, the touch event does not seem to happens.
I have searched several posts and fixes, but none of them made the touch event, or touch scroll from this iframe to work.
You can access my website through https://niltonsf.dev and on the top right select viewWebpage to focus on the html screen.
Here is the component in which renders the iframe:
import { Html } from "#react-three/drei";
import { Dispatch, SetStateAction } from "react";
import { isMobile } from "react-device-detect";
import * as THREE from "three";
interface MonitorProps {
geometry: THREE.BufferGeometry;
screen: THREE.Mesh;
bakedTexture: THREE.Texture;
setIsPointerOnHtml: Dispatch<SetStateAction<boolean>>;
isFocusOnHtml: boolean;
}
export default function Monitor({
geometry,
screen,
bakedTexture,
setIsPointerOnHtml,
isFocusOnHtml,
}: MonitorProps) {
return (
<>
<primitive object={screen}>
<group position={[-2.57, 1.8, -0.01]} rotation-y={1.565}>
<Html
transform
prepend
wrapperClass="htmlScreen"
scale={0.35}
distanceFactor={1.17}
zIndexRange={[0, 0]}
>
<div
onClick={(e) => {
if (!isFocusOnHtml) e.preventDefault();
}}
onPointerEnter={(e) => {
if (isFocusOnHtml) setIsPointerOnHtml(true);
}}
onPointerLeave={(e) => {
if (isFocusOnHtml) setIsPointerOnHtml(false);
}}
>
<iframe
id="iframe"
src="https://niltonsf.dev/static"
// src="http://192.168.1.13:3000/static"
title="myStaticWebsite"
style={{
width: isMobile ? 1200 : 1500,
}}
/>
</div>
</Html>
<mesh>
<planeGeometry args={[1.535, 0.69]} />
<meshPhysicalMaterial
blending={THREE.NoBlending}
opacity={0}
color={"black"}
side={THREE.DoubleSide}
/>
</mesh>
</group>
</primitive>
<mesh geometry={geometry}>
<meshBasicMaterial map={bakedTexture} />
</mesh>
</>
);
}
This is the main css file:
#root {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: white;
-webkit-overflow-scrolling: touch;
}
.htmlScreen iframe {
height: 700px;
border: none;
background: #000;
overflow-y: scroll;
touch-action: touch;
}
canvas {
touch-action: touch;
}
EDIT: It seems to be something with iPhones, Android devices work correctly
Am trying Electron and React, so i have encountered with an issue using React's ImageGallery component by putting "react-image-gallery": "^1.2.7" in package.json
There is a wrapper root and two blocks inside. the first block is the green bar. the second block is an Image Gallery.
The problem is: when the window size is reduced by moving the bottom border up so the bottom border overlap the second block (image gallery), so the half Image and thumbs are lost.
Notice: height of the lost area the same as the height of the first block h1=h2. If the height of the green block is close to 0 then there is no problem.
Could anyone assist with it?
See github repo or code below:
import { MemoryRouter as Router, Routes, Route } from 'react-router-dom';
import './App.css';
import ImageGallery from "react-image-gallery";
import "react-image-gallery/styles/css/image-gallery.css";
const Hello = () => {
var images = [
{
original: 'https://source.unsplash.com/2ShvY8Lf6l0/800x599',
thumbnail: 'https://source.unsplash.com/2ShvY8Lf6l0/800x599',
},
{
original: 'https://source.unsplash.com/NQSWvyVRIJk/800x599',
thumbnail: 'https://source.unsplash.com/NQSWvyVRIJk/800x599',
},
]
return (
<div>
<div className="comp1"/>
<ImageGallery
thumbnailPosition={"bottom"}
useBrowserFullscreen={false}
showPlayButton={false}
showNav={true}
showIndex={true}
items={images}
/>
</div>
);
};
export default function App() {
return (
<Router>
<Routes>
<Route path="/" element={<Hello />} />
</Routes>
</Router>
);
}
/** #NOTE: Prepend a `~` to css file paths that are in your node_modules*/
/** See https://github.com/webpack-contrib/sass-loader#imports*/
* {
box-sizing: border-box !important;
}
html, body {
height: 100%;
}
body {
font-size: 0.85em;
font-family: 'Roboto', sans-serif;
margin: 0;
}
#root {
min-height: 100%;
display: flex;
flex-direction: column;
}
.comp1 {
height: 50px;
background-color: yellowgreen;
}
I'm using Prismjs alongside Mdx for a code-related blog. I'm using it to show code blocks in a manner consistent with other blogs.
I'm running into an issue where the rendered code blocks (inside a <pre> element are too wide on my mobile layout. For now I am content to have things scroll on the horizontal axis. I'm 99% certain that the <pre> elements are what's breaking the layout because when I comment them out of the blog post, the layout works as expected.
Specifically, I'm using a package called prism-react-renderer (alongside Gatsby), and the code I have for the CodeBlock element (that handles the syntax highlighting) is more or less verbatim from the documentation for prism-react-renderer, but is included here for convenience:
import React from 'react'
import Highlight, { defaultProps } from 'prism-react-renderer'
import theme from 'prism-react-renderer/themes/nightOwl'
const CodeBlock = (props) => {
const className = props.children.props.className || ''
const matches = className.match(/language-(?<lang>.*)/)
return (
<Highlight {...defaultProps} code={props.children.props.children.trim()} language={
matches && matches.groups && matches.groups.lang
? matches.groups.lang
: ''
}
theme={theme}>
{({ className, style, tokens, getLineProps, getTokenProps }) => (
<pre className={className} style={{ ...style }}>
<code>
{tokens.map((line, i) => (
<div key={i} {...getLineProps({ line, key: i })}>
{line.map((token, key) => (
<span key={key} {...getTokenProps({ token, key })} />
))}
</div>
))}
</code>
</pre>
)}
</Highlight>
)
}
export default CodeBlock
This is the component used in the blog post template that handles rendering the .mdx files into HTML:
import React from 'react'
import { Link, graphql } from 'gatsby'
import { MDXRenderer } from 'gatsby-plugin-mdx'
import { MDXProvider } from '#mdx-js/react'
import Layout from '../components/layout'
import CodeBlock from '../components/code-block'
const components = {
pre: CodeBlock
}
const BlogPostTemplate = ({ data, pageContext, location }) => {
const post = data.mdx
const { previous, next } = pageContext
return (
<Layout>
*** Removed irrelevant component ***
<MDXProvider components={components}>
<div className='blog-post-wrapper'>
<article className='blog-post-content'>
<header>
<h1>
{post.frontmatter.title}
</h1>
<time dateTime={post.frontmatter.date}>
{post.frontmatter.date}
</time>
</header>
<MDXRenderer>{post.body}</MDXRenderer>
</article>
<footer className='blog-post-footer'>
*** Removed irrelevant components ***
</footer>
</div>
</MDXProvider>
</Layout>
)
}
export default BlogPostTemplate
I have tried a few different things: flex shrink, applying overflow-x: scroll and overflow-x: auto to both the <pre> element and its parents. When I apply a fixed width to the <pre> element and overflow-x: scroll I can get the behavior I want but I'd like to not have to use a fixed width on this if possible. The .css I have looks like this, including some obviously ineffectual styles:
.blog-post-wrapper {
display: flex;
flex-direction: column;
overflow-y: scroll;
overflow-x: scroll;
}
.blog-post-content {
flex-grow: 1;
margin-bottom: 2rem;
width: 100%;
display: flex;
flex-direction: column;
overflow-y: scroll;
overflow-x: scroll;
}
.blog-post-content .prism-code {
padding: 20px;
border: 3px solid red;
flex-shrink: 1;
overflow-y: scroll;
overflow-x: scroll;
}
I'll attach images of the way the <pre> element is rendering presently, in inspector:
And this is how it looks if I set a fixed width (in inspector):
It's probably too late, but I had the same issue and I was able to fix it by
Adding max-width css property to the main layout. The value should be equal to window.screen.width. I had to use the following hack to be able to get the screen size:
const [windowWidth, setWindowWidth] = useState(width)
useEffect(() => {
setWindowWidth(window.screen.width)
}, [])
Adding overflow: scroll to the pre in the CodeBlock
Not ideal, but I found this combination of CSS properties working together:
pre code {
display: inline-block;
width: 80vw;
overflow-x: auto;
}
This is a simple todo app built with react, bulma, and css grid. When I reload the page in chrome the height of the input form changes from 385x27.27 to 385x58.45, and lowers itself to the point of breaking through the bottom boundary of my css grid. I don't think this has much to do with my react code since I tested my app in firefox and edge which did not have this issue.
I also tried clearing my cache, cookies etc. for chrome which did not fix the issue. Surprisingly as soon as you type something into the input box (just typing) it fixes itself to the proper proportions. But as soon as you refresh, it breaks again. I should also note that it's broken on first render of the page (not just refreshing).
I suspect it has to do with my grid and how I wrapped the html elements (I'm still learning), or maybe event.prevent.default() and .reset() inside my react code are interfering with grid? I'm really not sure, and without error messages this has been hard to troubleshoot. I included the full code for my app below and images of the problem.
Page first loaded or refreshed (broken)
Page after typing "p" into the input (correct)
Index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.8.2/css/all.css" integrity="sha384-oS3vJWv+0UjzBfQzYUhtDYW+Pj2yciDJxpsK1OYPAYjqT085Qq/1cq5FLXAZQ7Ay" crossorigin="anonymous">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.5/css/bulma.min.css">
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<title>React App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
</html>
App.js
import React, { Component } from 'react';
import './App.css';
/* InputTaskForm renders a form, and returns the input to our storeTask method. */
const InputTaskForm = ({ formValidation }) => {
return (
<form name="charlie" className="charlie" onSubmit={formValidation}>
<input name="userinput" type="text" placeholder="Task..." size="35"/>
<button className="button is-info is-small" type="submit">Submit</button>
</form>
);
}
const DisplayTasks = ({ tasksArray, removeTask, crossOutTask }) => {
return (
<div id="orderedList">
<ol>
{/* Create our list items and corresponding buttons by mapping over the tasks array. The array is currently made up of objects with a title and crossedOut key. Therefore keep in mind the task prop is carrying objects, not the task title itself */}
{tasksArray.map((task, index) => (
<li onClick={ () => crossOutTask(index) } key={index} >
{/* Check the crossedOut value of the current task object. If crossedOut is true display it crossed out, else display it uncrossed */}
{ task.crossedOut
? <strike>{task.title}</strike>
: task.title }
<button className="removeButton button is-danger is-small" onClick={ event => removeTask(event, index) } >Remove</button>
</li>
))}
</ol>
</div>
);
};
class App extends Component {
state = {
userinput: '',
tasksarray: [],
}
/* ============================================== #FUNCTIONS ==============================================
=========================================================================================================== */
formValidation = event => { // event prop passed from InputTaskForm component
event.preventDefault(); // prevent form from auto-refreshing on submit
const userInput = event.target.userinput.value // userInput stored
const userInputIsBlank = userInput.trim().length < 1 // trim (remove) prefixed and affixed spaces, then check length
userInputIsBlank
? alert(`Error: invalid submission`)
: this.storeTask(userInput);
};
storeTask = userInput => { // userInput passed from formValidation function
this.setState({
userinput: userInput,
tasksarray: [...this.state.tasksarray, { title: userInput, crossedOut: false } ] //create a copy of tasks array then add a new object into the array filled out with user input
});
document.forms["charlie"].reset();
};
removeTask = (event, index) => { // props passed from DisplayTasks component
event.stopPropagation(); // prevents bubbling to crossOutTask in the DisplayTask component
const removedTaskArray = [...this.state.tasksarray]; //removedTaskArray is just a copy of our current array for the moment
removedTaskArray.splice(index, 1); //here removedTaskArray actually becomes an array w/ the removed task (removed with splice)
this.setState({ tasksarray: removedTaskArray });
};
crossOutTask = index => { // index prop passed from DisplayTasks component
const { tasksarray } = this.state
const selected = tasksarray[index];
this.setState({
tasksarray: [ // change tasksarray state to: [prior slice, change, after slice]
...tasksarray.slice(0, index), // slice off (copies) of array elements prior to index element
Object.assign(selected, {crossedOut: !selected.crossedOut}), // invert the selected line's crossedOut value
...tasksarray.slice(index + 1) // slice off (copies) of array elements after index element
]
});
};
componentDidUpdate() {
console.log(this.state.tasksarray); // debugging :)
};
/* =============================================== #RENDER ================================================
=========================================================================================================== */
render() {
const { tasksarray } = this.state
const { formValidation, storeTask, removeTask, crossOutTask } = this
return (
<div className="grid-container">
<div className="input-tasks-container box">
<h1 className="title is-4">Todo: </h1>
<InputTaskForm
task={storeTask}
formValidation={formValidation} />
</div>
<div className="tasks-grid-container">
<h1 className="Tasks-title title is-4">Tasks</h1>
<h1 className="Tasks-title subtitle is-6">Tip: click on a task to mark it as done</h1>
<DisplayTasks
tasksArray={tasksarray}
removeTask={removeTask}
crossOutTask={crossOutTask} />
</div>
</div>
);
};
};
/* ================================================ #EXPORT ===============================================
=========================================================================================================== */
export default App;
App.css
/* Prevent highlighting when double clicking list items */
#orderedList {
-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 */
cursor: pointer;
}
.grid-container {
display: grid;
grid-template-columns: 1fr 1fr 425px 1fr 1fr;
grid-template-rows: 200px 1fr;
}
.input-tasks-container {
margin-top: 45px;
text-align: center;
display: grid;
grid-column-start: 3;
}
.Tasks-title {
margin-top: 20px;
}
.tasks-grid-container {
display: grid;
grid-row-start: 2;
grid-column-start: 3;
grid-column-end: 5;
}
.removeButton {
margin-left: 10px
}
button {
cursor: pointer;
}
.charlie {
margin-bottom: 20px;
}
li {
margin-bottom: 10px;
}
ol {
margin-left: 40px;
}
In my website, I am using fancybox 2.1.5. when I open an image and close it I return to the top of the page unintentionally. The problem can be seen in the following minimal example
<!DOCTYPE html>
<head>
<style media="screen" type="text/css">
body {
height: 100%;
}
html {
height: 100%;
}
</style>
<link rel="stylesheet" type="text/css" href="css/jquery.fancybox.css?v=2.1.5" media="screen" />
</head>
<body>
<a href=#>
<img src="http://placehold.it/1000x600">
</a>
<a class="fancybox" href="img/Gallery/500x600.gif">
<img src="http://placehold.it/500x600">
</a>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script type="text/javascript" src="js/jquery.fancybox.js?v=2.1.5"></script>
<script>
$(document).ready(function() {
$('.fancybox').fancybox();
});
</script>
</body>
</html>
You will see that if you open and close the second image you will find yourself at the top of the page.
It appears that if I delete the initial style in the head
<style media="screen" type="text/css">
body {
height: 100%;
}
html {
height: 100%;
}
</style>
The problem disappears. if I erase only the body style or the html style the problem also disappears. In order for the problem to appear both body and html heights must be to 100%
Unfortunately I don't understand why this is happening. Can someone please explain?
Note: I have found solutions and hacks to this problem but I would like to understand why this is happening
Update: seems not to work if you trigger the Fancybox while on a URL that points to a tag with an ID (e.g., "https://example.com/#currentsection"). When you exit the Fancybox, it doesn't go to the top of the page, but does scroll to the top of the tag with the ID, even if you've set the autoFocus and placeFocusBack options to false. Strangely, it still works if your URL is pointed at #top.
Original answer
I found that when using Fancybox in Next.js, binding or configuring Fancybox with autoFocus set to false fixed this. It then seems that placeFocusBack property (default: true) will apply. Set it up like so:
npm install --save #fancyapps/ui
components/fancybox-wrapper.js:
// Fancybox UI wrapper for lightbox
// Thanks to https://fancyapps.com/docs/ui/fancybox/react
import React, { useEffect } from "react";
import { Fancybox as NativeFancybox } from "#fancyapps/ui/dist/fancybox.esm.js";
function Fancybox(props) {
const delegate = props.delegate || "[data-fancybox]";
useEffect(() => {
const opts = props.options || {};
NativeFancybox.bind(delegate, opts);
return () => {
NativeFancybox.destroy();
};
}, []);
return <>{props.children}</>;
}
export default Fancybox;
pages/_app.js:
import Fancybox from "../components/fancybox-wrapper";
import "#fancyapps/ui/dist/fancybox.css";
import { SSRProvider } from "#react-aria/ssr";
function MyApp({ Component, pageProps }) {
return (
<SSRProvider>
<Fancybox options={{ infinite: false, autoFocus: false }}>
<Component {...pageProps} />
</Fancybox>
</SSRProvider>
);
}
export default MyApp;
You can use native helper of fancy box to fix returning to top of page problem.
$('.fancybox').fancybox({
padding: 0,
helpers: {
overlay: {
locked: false
}
}
});
reference : http://davekiss.com/prevent-fancybox-from-jumping-to-the-top-of-the-page/