I would like to use styled-components in a React app to create a menu component that contains the styles in the same file thus making it very modular. I'm using react-burger-menu for the menu. Everything works correctly if I wrap BurgerMenu in a styled div like so (styles copied from react-burger-menu README.md):
import React from 'react';
import { slide as BurgerMenu } from 'react-burger-menu';
import styled from 'styled-components';
const StyledBurgerMenu = styled.div`
/* Position and sizing of burger button */
.bm-burger-button {
position: fixed;
width: 36px;
height: 30px;
left: 36px;
top: 36px;
}
/* Color/shape of burger icon bars */
.bm-burger-bars {
background: #373a47;
}
/* Position and sizing of clickable cross button */
.bm-cross-button {
height: 24px;
width: 24px;
}
/* Color/shape of close button cross */
.bm-cross {
background: #bdc3c7;
}
/* General sidebar styles */
.bm-menu {
background: #373a47;
padding: 2.5em 1.5em 0;
font-size: 1.15em;
}
/* Morph shape necessary with bubble or elastic */
.bm-morph-shape {
fill: #373a47;
}
/* Wrapper for item list */
.bm-item-list {
color: #b8b7ad;
padding: 0.8em;
}
/* Individual item */
.bm-item {
display: inline-block;
}
/* Styling of overlay */
.bm-overlay {
background: rgba(0, 0, 0, 0.3);
}
`;
export class Menu extends React.Component {
showSettings(event) {
event.preventDefault();
}
render() {
return (
<StyledBurgerMenu>
<BurgerMenu>
<a id="home" className="menu-item" href="/">Home</a>
<a id="about" className="menu-item" href="/about">About</a>
</BurgerMenu>
</StyledBurgerMenu>
);
}
}
export default Menu;
Now this is of course totally okay. However, to learn a lesson and make things a bit more elegant, I'd like to get rid of nesting BurgerMenu inside of StyledBurgerMenu by passing the former to styled(). However, this leads to the burger button being not styled (as per the docs, it's overlaid transparently across all of the screen, so I can click anywhere to open the menu and see that everything else is styled correctly). Is it possible to style the burger button in this fashion or do I have to use the outer div? Here is how I've tried to solve this:
import React from 'react';
import { slide as BurgerMenu } from 'react-burger-menu';
import styled from 'styled-components';
const StyledBurgerMenu = styled(BurgerMenu)`
/* Position and sizing of burger button */
.bm-burger-button {
position: fixed;
width: 36px;
height: 30px;
left: 36px;
top: 36px;
}
/* Color/shape of burger icon bars */
.bm-burger-bars {
background: #373a47;
}
/* Position and sizing of clickable cross button */
.bm-cross-button {
height: 24px;
width: 24px;
}
/* Color/shape of close button cross */
.bm-cross {
background: #bdc3c7;
}
/* General sidebar styles */
.bm-menu {
background: #373a47;
padding: 2.5em 1.5em 0;
font-size: 1.15em;
}
/* Morph shape necessary with bubble or elastic */
.bm-morph-shape {
fill: #373a47;
}
/* Wrapper for item list */
.bm-item-list {
color: #b8b7ad;
padding: 0.8em;
}
/* Individual item */
.bm-item {
display: inline-block;
}
/* Styling of overlay */
.bm-overlay {
background: rgba(0, 0, 0, 0.3);
}
`;
export class Menu extends React.Component {
showSettings(event) {
event.preventDefault();
}
render() {
return (
<StyledBurgerMenu>
<a id="home" className="menu-item" href="/">Home</a>
<a id="about" className="menu-item" href="/about">About</a>
</StyledBurgerMenu>
);
}
}
export default Menu;
Thanks!
Is it possible to style the burger button in this fashion or do I have
to use the outer div?
By passing your BurgerMenu to styled, you are not adding an outer div, the styled component only ensures your css is added to the document and passes the className to BurgerMenu. So in order for this to work, BurgerMenu has to render its className prop. If it does that it will work without an outer div (or any other parent).
According to https://github.com/negomi/react-burger-menu/blob/95a58dd41e546730f5661dd7ad8deb7296a725ff/src/menuFactory.js#L251 it assigns its className prop to an inner div, which is not ideal for styled-components but your styles will apply to that div. If you want to style the other elements at or above that level, you will either need to come up with some fancy selectors or assign them from outside.
This is not possible because of the way styled-components work
The styling is being applied to a child div, not the outer div:
Link to code in react-burger-menu
Related
I'm using React and javascript to style my webpage, and I have implemented a skip link in my navbar that takes the user further down the page when clicked. This skip link only comes into focus when the user hits the tab key, but it is positioned above the site logo in the navbar and so needs more space when it is visible. I want to increase the height of my navbar when the link is visible, and right now I am using a boolean called linkHasFocus (for some conditional CSS styling), along with a function called checkFocus, to do that:
const TopNavbar = styled. div`
...
height: ${props => (props.linkHasFocus ? '9rem' : '4rem')};
...
`;
And here's the checkFocus function:
const checkFocus = () => {
const elem = document.getElementById('skip-link');
if (elem === document.activeElement) {
this.linkHasFocus = true;
}
this.linkHasFocus = false;
return this.linkHasFocus;
};
I then pass this to my TopNavbar component (which is the parent of my skip link component) in my return function like so:
<TopNavbar linkHasFocus={checkFocus}>
But it seems the checkFocus function isn't updating the linkHasFocus variable correctly. My understanding of props and javascript in general is a little shaky, so apologies if there's glaring issues here.
I've got this navbar example from w3schools.com (I suggest you to check the Top Navigation tutorial), and I've extended it with 3 examples, showing how you can expand it with JavaScript and CSS.
By using the property .classList we can .add(), .remove() or .toggle() classes from elements. Then we can add some style content to enhance them (by adding a different height and a transition for the topnav, for example) when a certain action is performed.
The following JavaScript snippet shows 3 examples:
expand the Navbar while we are pressing TAB key (keyCode == 9), and shrink it while that key is up;
toggle the expand when the SPACE key (keyCode == 32) is pressed;
expand the Navbar while the mouse is hovering the Skip section, and shrink it while the mouse leaves the area.
// example 1: expand the navbar while tab key is pressed
document.body.addEventListener("keydown", function(e) {
if(e.keyCode == 9) {
document.getElementById("myTopnav").classList.add("expand");
}
});
document.body.addEventListener("keyup", function(e) {
if(e.keyCode == 9) {
document.getElementById("myTopnav").classList.remove("expand");
}
});
// example 2: toggle navbar expand with space key
document.body.addEventListener("keydown", function(e) {
if(e.keyCode == 32) {
document.getElementById("myTopnav").classList.toggle("expand");
}
});
// example 3: expand the navbar while the mouse is over
document.getElementById("skip").addEventListener("mouseover", function(e) {
document.getElementById("myTopnav").classList.add("expand");
});
document.getElementById("skip").addEventListener("mouseout", function(e) {
document.getElementById("myTopnav").classList.remove("expand");
});
body {
margin: 0;
font-family: Arial, Helvetica, sans-serif;
}
.TopNavbar {
height: 4rem;
overflow: hidden;
background-color: #333;
-webkit-transition: all .5s ease;
transition: all .5s ease;
}
#myTopnav.expand {
height: 9rem;
transition: height 300ms;
}
.TopNavbar a {
float: left;
display: block;
color: #f2f2f2;
text-align: center;
padding: 14px 16px;
text-decoration: none;
font-size: 17px;
}
.TopNavbar a:hover {
background-color: #ddd;
color: black;
}
.TopNavbar a.active {
background-color: #04AA6D;
color: white;
}
.pageContent {
padding: 14px 16px;
}
li {
margin: 10px 0;
}
<html>
<head>
</head>
<body>
<div class="TopNavbar" id="myTopnav">
Home
Contact
About
<a id="skip" href="#skip">Skip</a>
</div>
<div class="pageContent">
<h3>Navbar extension example</h3>
<ul>
<li>Example 1: extend the navbar while <code>TAB</code> key is pressed.</li>
<li>Example 2: press <code>SPACE</code> key to toggle the navbar extend.</li>
<li>Example 3: extend the navbar while the mouse is over "Skip" option.</li>
</ul>
</div>
</body>
</html>
If that still isn't what you're looking for, you could have a look at CSS Selectors and search if there's something that suits your page.
I am creating a basic nav bar and I want to change it based on screen size. Once it hits 600px i'd like to hide the links and display a clickable nav button that will expand those options.
After console logging my list Elements I found that the className was given this 'Nav_floatLeft__H1YZ8'. So based on that finding, my code is as follows. However, my navigation does not display any changes when clicking the button.
I'm sure React has a better way of handling this situation, but I'm fairly new to it. Should I be using some kind of state/effect hook?
Nav:
const openCloseMenu = () => {
console.log(document.getElementsByClassName(styles.floatLeft).className);
let elements = document.getElementsByClassName(styles.floatLeft);
if (elements.className === "Nav_floatLeft__H1YZ8"){
alert("Changed to: Menu Bar Expanded");
elements.className = styles.menuBarExpanded;
}
else {
alert("Changed Back to: Float Left")
elements.className = styles.floatLeft;
}
}
return (
<div className={styles.topNav}>
<nav>
<ul className={styles.inlineListItem}>
<li className={styles.floatLeft}>
<Link href="/">
<a>Home</a>
</Link>
</li>
<li className={styles.floatLeft}>
<Link href="/search">
<a>Search</a>
</Link>
</li>
<li className={styles.menuBar}>
<button onClick={openCloseMenu}>Expand Nav</button>
</li>
</ul>
</nav>
</div>
)
CSS:
.inlineListItem{
display: inline;
list-style: none;
}
.floatLeft{
float: left;
margin: 1rem;
padding-left: 1rem;
text-align: center;
color: white;
}
.floatRight{
display: inline;
float: right;
color: white;
margin: 1rem;
padding-right: 2rem;
}
.menuBar{
display: none;
float: left;
margin: 1rem;
padding-left: 1rem;
text-align: center;
color: white;
}
.menuBarExpanded{
display: block;
}
#media screen and (max-width: 600px) {
.menuBar{
display: block;
}
.floatLeft{
display: none;
}
.floatRight{
display: none;
}
}
ways are there to solve this problem.
You can use material UI. To detect the breakpoint.
Like for you case. If want to detect 600px.
you can do something like that ---
const themeBreakpoint = theme.breakpoint.down('600px) // themeBreakpoint will be true under 600px.
using this flag you can change state and show what ever you want by using condition rendering.
Second Problem --
you can change any state based on onClick event.
like --
const[clicked,setclicked] = useState(false)
const handleClick = (e) =>{
setclicked(true)
}
now when you make that clicked flag true, You change you css class based on that flag.
You could implement an useState hook:
import { useState } from "react";
const YourComponent = () => {
const [cliked, setClicked] = useState(false);
return (
<YourNavbar className={clicked ? "display" : "hide"} />
....
<button onClick={() => setClicked(current => !current)}>Expand Nav</button>
....
)
}
And on css, you can establish the class display with the actual attributes of the navbar, and a hidden (display: none)
This will check if the navbar button has been clicked (set to true), and on the conditional class, if its true, then it will display the navbar through the "display" class, if the button is clicked again, clicked will be false and the class for the navbar will be "hidden".
Remember to delegate this classnames to the item only when the navbar is below 600px with #media
I've just included react-h5-audio-player into my project and following the README page to customise the styles by overwriting the SCSS variables responsible for the colours.
However it seems like my styles just get ignored. Do you have any idea what could be going wrong here? Thank you very much.
This is the codesandbox where I've reproduced the problem: https://codesandbox.io/s/react-and-scss-forked-yeu0q?file=/src/index.js
As you can see I've included the style.css (which contains the overwritten variables) in 3 places -- before importing audioplayer's js, before importing audioplayer's css and after both of these just in case to see if any of these works. I also randomly added !default and !important to the variables hoping that at least some of the syntax would work, but the styles are just keep being ignored.
I will also include the code to this post if someone prefers seeing it here rather in codesandbox:
style.css:
html,
body {
background-color: papayawhip;
font-family: sans-serif;
h1 {
color: tomato;
}
}
$rhap_theme-color: #ff0000; // Color of all buttons and volume/progress indicators
$rhap_background-color: #ff0000 !important; // Color of the player background
$rhap_bar-color: #ff0000 !default; // Color of volume and progress bar
$rhap_time-color: #0000ff !important !default; // Font color of current time and duration
$rhap_font-family: inherit !important; // Font family of current time and duration
index.js:
import React from "react";
import { render } from "react-dom";
import "./styles.scss";
import AudioPlayer from "react-h5-audio-player";
import "./styles.scss";
import "react-h5-audio-player/src/styles.scss";
import "./styles.scss";
const App = () => (
<div>
<h1>Hello</h1>
<AudioPlayer src="http://example.com/audio.mp3" />
</div>
);
render(<App />, document.getElementById("app"));
For another approach you can use this example:
.rhap_container {
background: #f7f7f9;
}
.rhap_controls-section {
margin-bottom: 15px;
}
.rhap_progress-section {
height: 20px;
padding-bottom: 20px;
}
.rhap_main-controls-button {
width: 80px !important;
height: 80px !important;
}
.rhap_main-controls-button {
width: 56px;
height: 56px;
display: block;
}
.rhap_main-controls-button svg {
color: #ff5555;
width: 100%;
height: 100%;
}
.rhap_progress-filled,
.rhap_progress-indicator {
background-color: #ff5555 !important;
}
.rhap_button-clear.rhap_volume-button {
color: #ff5555 !important;
}
.rhap_volume-bar, .rhap_volume-indicator {
background-color: red;
}
I have build sidebar with css and jquery. It's working fine but i want that when sidebar opens then whole screen except sidebar should get semi-black or disabled.
Here is my working
jsFiddle
How can i make whole screen semi-black or disabled on sidebar open?
You can use a box-shadow on the sidebar:
#sidebar{
box-shadow:0 0 0 10000px rgba(0,0,0,.50);
}
This is black, at .50 opacity. It's set to 10000px to cover the full screen.
Or change rgba(0,0,0,.50) to a solid color like #5a5a5a.
In your case add to your css:
#slide-out.visible:not(.close){
box-shadow:0 0 0 10000px #666666;
}
The general concept to achieve this is fairly straightforward:
Modify the javascript to add a class to the body when the nav is open (I called it nav-open.)
Modify the CSS so that the "overlay" element (you already had one in place) is displayed when the body has the class nav-open
Adjust your overlay element CSS to cause it to show properly (for some reason, it had opacity: 0 on it, which meant it was there, but was not visible).
Here's the relevant CSS:
#sidenav-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
width: 100vw;
height: 100vh;
// removed opacity: 0;
background-color: rgba(0, 0, 0, 0.5);
z-index: 997;
// set display to none by default
display: none;
}
// when the body has the class nav-open, display the overlay
.nav-open #sidenav-overlay {
display: block;
}
Here's the relevant changes to your javascript:
// no-conflict-safe document ready function
jQuery(function($) {
$('#show-hide-menu').click(function() {
if ($('#slide-out').hasClass('visible')) {
// $('#slide-out').removeClass('visible');
$('#slide-out').toggleClass('close');
} else {
$('#slide-out').addClass('visible');
}
// check if the nav is "open"
var open = !$('#slide-out').hasClass('close');
// for simplicity, always first remove the nav-open from the body
$('body').removeClass('nav-open');
// if the nav is open, add the 'nav-open' class to the body
if (open) {
$('body').addClass('nav-open');
}
});
// modify to use "on", is best-practice
// $(document).click(function(e) {
$(document).on('click', function(e) {
var sidebar = $(".sidenav, #show-hide-menu");
if (!sidebar.is(e.target) && sidebar.has(e.target).length === 0) {
$('#slide-out').toggleClass('close');
// be sure the nav-open class is removed when the sidebar is dismissed
$('body').removeClass('nav-open');
}
});
});
Here is a link to your fiddle, modified with these changes to do what you want: http://jsfiddle.net/cale_b/hThGb/8849/
Make a content div below your nav. Something like:
<div id="maincontent" class="">
<p>Lorem.</p>
</div>
Add some styling so it has min-height, etc.
#maincontent {
width: 100%;
height: 100%;
padding: 0;
margin: 0;
min-height: 400px;
}
Add some JS so when the nav menu button is clicked, it toggles on and off a new style class for this area.
$('#show-hide-menu').click(function () {
if ($("div#maincontent").hasClass("overlayed")) {
$("div#maincontent").removeClass("overlayed");
}
else {
$("div#maincontent").addClass("overlayed");
}
});
Define the overlayed class in the CSS.
.overlayed {
background-color: rgba(0,0,0,.8);
}
I have 2 divs side by side and by default one is hidden and one is visible.
I have a jQuery function which, when mouseenter the visible div, the hidden one shows. And when mouseenter again, it becomes hidden again. (This is for a login box)
However - I want the always visible div (the mouseenter target) to change color depending on what state the toggled div is in. So far, I can get it to change color upon first mouseenter but it won't change again after that.
Here is the code I have so far:
<script>
$(document).ready(function () {
$("#loginBox").hide();
$("#sideBar").show();
$('#sideBar').mouseenter(function () {
$("#loginBox").toggle("slide");
if ($('#loginBox').is(":visible")) {
$("#sideBar").css("background-color","blue");
} else if ($('#loginBox').is(":hidden")) {
$("#sideBar").css("background-color","yellow");
}
});
});
</script>
So it starts off in its default color (grey by the style sheet) and when mouseenters it loginBox becomes visible and the sideBar turns blue. But when mouseenters again, even though loginBox becomes hidden, the sideBar remains blue.
JSFiddle
You can put the check in the complete function of toggle
$(document).ready(function() {
$("#aside").hide();
$("#asidebar").show();
$('#asidebar').mouseenter(function() {
$("#aside").toggle("slide", function() {
var onOrOff = $('#asidebar').css("background-color");
if ($('#aside').is(":visible")) {
$("#asidebar").css("background-color", "blue");
} else if ($('#aside').is(":hidden")) {
$("#asidebar").css("background-color", "yellow");
}
});
});
});
#asidebar {
float: right;
/* top: -205px; */
position: relative;
/*
Editing purposes */
background-color: rgba(120, 120, 120, 0.5);
width: 25px;
/*min height of container */
height: 400px;
margin: 5px;
padding: 1px;
font-family: helvetica;
}
#aside {
float: right;
/* top: -205px; */
position: relative;
/*
Editing purposes
background-color: blue; */
width: 250px;
border-left-style: dashed;
border-color: rgba(120, 120, 120, 0.5);
/*min height of container */
margin: 5px;
padding: 0;
font-family: helvetica;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="asidebar">Mouse Over</div>
<div id='aside'>Slide box</div>
You are better off putting the styles on a class and toggling that instead. Something like
...
$('#sideBar').mouseenter(function () {
$("#loginBox").toggle("slide");
$("#sideBar").addClass("semanticallyNamedClassForBlue");
$("#sideBar").toggleClass("semanticallyNamedClassForYellow");
});
...
CSS:
#sideBar.semanticallyNamedClassForBlue {background: blue}
#sideBar.semanticallyNamedClassForYellow {background: yellow}
as per this jsfiddle adapted from user3787555's http://jsfiddle.net/3rQNb/3/
Explanation:
On load the sidebar is grey.
on first hover both the yellow and blue classes are added to the element, but as the yellow class is last in the css source, it wins the cascade.
on next hover, the yellow class is removed, so the blue now wins.
I added the id to the css rule to get the specificity up enough - as you know a #id beats a .class in the cascade
If you want to learn more, A List Apart's CSS articles and Remy Sharp's JQuery for designers may give you some joy. If you want to learn more on specificity look at star wars specificity super awesome