Building a 'more' mobile responsive menu - html

I am a big fan of this particular style of mobile menu: https://www.w3schools.com/html/default.asp
Reason being even on mobile layouts, depending on the size of the page, it still shows some main navigation items. That way I think you could perhaps show some of your most popular links, without the user having to go into the mobile menu.
I am trying to recreate this behavior with react.
To keep the example simple: I return all my links from a map statement and render it in the layout:
getNavigationItems(){
const items = this.props.routes.slice(0, this.state.cutOffIndex).map((link) =>
<a
className="DNavigationContainer-LinkItem"
href="#"
>{link.title}</a>
);
return items;
}
That 'cutOffIndex' is used to determine if I should only be showing a subset of items. As my page width gets smaller, I decrement the cutoff index to show less and less.
That works well, the only issue is some of these links are different sized (based off the amount of text).
I need a solution that would understand how big each link is, therefore I understand how many links I can show without being over the width.
I thought about in the constructor of my element looping through each link and storing the size in an array, and then recalling that array (when say I have 300 pixels to work with, get as many elements that I can that would be shorter than 300 pixels combined).
for(var i = 0; i < this.props.routes.length; i++){
var textLength = this.props.routes[i].title.length;
//store this text length in an array?
}
However, this seems overcomplicated, and I wonder if there is a simplier way to do this in CSS? Or a prefered approach?

You can hide elements based on screen size with CSS property overflow: hidden.
nav {
width: 100%;
border: 1px solid #000;
}
a {
display: inline-block;
height: 30px;
background: #fff;
padding: 5px 15px;
box-sizing: border-box;
}
.left {
overflow: hidden;
height: 30px;
}
.right {
overflow: hidden;
float: right;
}
<nav>
<div class="right">
Always visible
</div>
<div class="left">
Link 1
Link 2
Link 3
Link 4
Link 5
Link 6
Link 7
Link 8
Link 9
Link 10
Link 11
Link 12
</div>
</nav>
When there is not enough space in .left element, links will be wrapped to the next line. Property overflow: hidden ensure that those elements are not visible.
Fiddle: https://jsfiddle.net/ojgbvq5c/

Related

Can I allow inline-block elements to split across lines?

I'd like to have links zoom in when the mouse hovers on them, I've tried with transform unsuccessfully, but then I found this answer, which looked promising.
However, making an inline element an inline-block also seems to prevent it from being split across several lines, as shown in the snippet below, which can create very unpleasant results for short width of the enclosing box.
div {
border: 1px solid black;
text-align: justify;
width: 20em;
}
a {
text-decoration: none;
display: inline-block;
}
a:hover {
transform: scale(1.01);
}
<div>
<p>Today, <a href="https://github.com/Aster89/WinZoZ">my
Vim plugin for easy window navigation</a>, which I named
WinZoZ,
has got its first star! Given <a
href="https://stackoverflow.com/questions/69007954/vim-remap-ctrl-w-in-insert-mode-to-behave-as-it-does-in-normal-mode#comment121984179_69007954">this
comment on StackOverflow</a>, the star is from the user #yolenoyer.
</p>
</div>
On the other hand, in this specific example above I see that the first link is so long that it does split across lines, so it looks like inline-block elements can indeed do that. How can allow it when they are shorter than the text width?
The animation missing is due to the original link (a tag) element not having the transition: property defined. Per the positioning documentation here it seems only inline-block is suitable for flowing text and that fails to show wrapped text, even with wrap: break-word; present. The inline-flex, inline-grid don't work either since they are both block display types.
One solution would be to break the text lines at certain points and setting different <br> elements to show at different #media widths for certain page widths/devices. However the inline-block elements cannot wrap like normal text, so the breaks just end up making it a 2-line block in the middle of the text.
div {
border: 1px solid black;
/* text-align: justify; */
width: 20em;
}
a {
text-decoration: none;
/* new */
transition: transform .15s; /* Animations: "transform" on a-tag must be present */
display: inline-block;
}
a:hover {
transform: scale(1.01); /* then we transform the transition here */
-ms-transform: scale(1.01); /* IE 9 */
-webkit-transform: scale(1.01); /* Safari 3-8 */
}
<div>
<p>Today, <a href="https://github.com/Aster89/WinZoZ">my
Vim plugin for easy window navigation</a>, which I named
WinZoZ,
has got its first star! Given <a
href="https://stackoverflow.com/questions/69007954/vim-remap-ctrl-w-in-insert-mode-to-behave-as-it-does-in-normal-mode#comment121984179_69007954">this
comment on StackOverflow</a>, the star is from the user #yolenoyer.
</p>
</div>
Some JS scripting
A breaking up of the line into blocks in a ul list with the li items being inline-block themselves could be a solution. A function to run at DOM load on each desired div's contents could do this. A loop for all a elements in those divs that transform each of the links into an array of words and puts the array items in a ul -> li. Perhaps there is a jQuery plugin for this already.
Light JS example
(not complete code, but using querySelectorAll, which could be used to gather the links from a <div> with a class you put as the function input):
<script type="text/javascript">
// function to look for a-tags in a DIV with a specific class
function linkToList(inputDivClass) {
// get the links inside the div with the input div class
const allLinks = document.querySelectorAll("div." + inputDivClass + " > a");
for (var i = allLinks.length; i < 0; i++) {
// here we go through the links returned from the div...
}
// then go through the data and see what to put where...
}
// when dom is loaded we run the function that looks for the divs with the a-tags...
document.addEventListener("DOMContentLoaded", linkToList(inputDivClass) );
</script>

Apply the siblings selector when the second operand has "hidden" attribute

Intro
The vue-slide-up-down plugin appends the attribute hidden to target element to hide it. According documentation, this method is preferred:
"use-hidden" property
Whether to apply the "hidden" attribute to the element when closed.
Defaults to true. This hides the component from the screen and from
assistive devices. The internal elements of the component are
completely invisible, and cannot be focused on (by a keyboard or
assistive device). (This is probably what you want!) If you need, set
this property to false to not use the hidden attribute. This could be
used if you wanted to have a min-height requirement on your component.
Note that this can create accessibility issues, specifically for users with a keyboard or screen reader.
🌎 Source
The problem is the element with hidden attribute obeys to Schrödinger paradox: "this elements is existing, but in the same time not existing". Below example shows what it means.
Target
When the ".ControlsGroup" (designated by blue) is visibly last, it must provide the vertical space l1 below self inside ".Container" (designated by light yellow):
When the ".ErrorsContainer" (designated by orange) is visible, it must retire l2 px from ".ControlsGroup" and provide vertical space l3 below self:
The usage of padding-bottom of container is not allowed because basically we don't know at advance what will be placed inside ".ControlsGroup", so each element MUST know:
How much to retire from specific previous element
How much of vertical space it needs to provide below self when going last.
<div class="Container">
<div class="ControlsGroup"></div>
<div class="ErrorsContainer"></div>
</div>
Problem
When ErrorsContainer is visible, everything is all right: in below example, l2 is 24px and l3 is 36px:
.Container {
background: #FFECB3;
overflow: auto;
}
.ControlsGroup {
height: 300px;
background: #03A9F4;
}
.ErrorsContainer {
height: 40px;
background: #FF9800;
margin-bottom: 36px;
}
.ControlsGroup + .ErrorsContainer {
margin-top: 24px;
}
🌎 Fiddle
Now, if to add hidden attribute to .ErrorsContainer, no l1 space (between bottom of .ControlsGroup and bottom of .Container) will be:
🌎 Fiddle
Let's try to add below CSS rule that means "when .ErrorsContiner with attribute hidden going after .ControlsGroup, push it to 12px (l3)":
.ControlsGroup + .ErrorsContainer[hidden="hidden"] {
margin-bottom: 12px;
}
Nothing will change. The effect like .ErrorsContainer does not exist.
Next, lets try to add below rule that means "When ControlsGroup going last, make 12px of extra space inside the parent":
.ControlsGroup:last-child {
margin-bottom: 12px;
}
Nothing will change because .ErrorContainer actually exists and it's the last child.
Now how to define the l3 when .ErrorsContainer is hidden?
We can do some math here and consider x where l1 + x = l2. The idea is to always have the l1 and when the ErrorsContainer is visible we add to it a margin-top equal to x to get l2 instead of l1. I will also use flexbox to avoid margin collapsing and make sure the margin add and not collapse.
I am using CSS variables to illustrate but it's not mandatory:
.Container {
--l1:30px;
--x:-15px; /* so l2 = 15px */
--l3:10px;
background: #FFECB3;
display:flex;
flex-direction:column;
overflow: auto;
border:2px solid;
margin:5px;
}
.ControlsGroup {
height: 100px;
background: #03A9F4;
}
.ErrorsContainer {
height: 40px;
background: #FF9800;
margin:var(--x) 0 var(--l3);
}
.ControlsGroup {
margin-bottom:var(--l1);
}
<div class="Container">
<div class="ControlsGroup"></div>
<div class="ErrorsContainer" hidden></div>
</div>
<div class="Container">
<div class="ControlsGroup"></div>
<div class="ErrorsContainer"></div>
</div>

How to hide nav bar on scroll and show a sidebar?

I am using bootstrap to code the frontend of a website. What I hope to achieve is that when I scroll the navbar vanishes and the sidebar pops up. I have been stuck on this for ages so If anyone has any idea to let me know.
This should answer the first piece of the question, in terms of hiding the navbar on scroll. I would get away from using bootstrap in this instance. It is easier to build your navbar from scratch, style it with css, and then use javaScript to manipulate it dynamically, such as hiding it. Once this is working. I can help you to get the sidebar to present on scroll. The link should give you an idea where to do with this.
https://www.w3schools.com/howto/howto_js_navbar_hide_scroll.asp
It is my opinion that the following block of javaScript will help you the most. you did not leave a code block, so it is only an assumption, based on what the common layout is. Again, I would move away from bootstrapping the menu bar, since you are wanting to customize features within it. You will see an explanation of the site that I listed below:
The first block would be your navbar div:
<div id="navbar">
Home
News
Contact
</div>
You can set this up and represent it however you would choose too. It should be in a standalone HTML file, lets say index.html for these purposes.
The next block of code is the CSS, as it would pertain to the above codeblock. Again, this can be shaped however you would like it to be, but for these purposes it is simply giving a blueprint. This should also be in a standalone css file.
#navbar {
background-color: #333; /* Black background color */
position: fixed; /* Make it stick/fixed */
top: 0; /* Stay on top */
width: 100%; /* Full width */
transition: top 0.3s; /* Transition effect when sliding down (and up) */
}
/* Style the navbar links */
#navbar a {
float: left;
display: block;
color: white;
text-align: center;
padding: 15px;
text-decoration: none;
}
#navbar a:hover {
background-color: #ddd;
color: black;
}
The final code block is your script. The JS that will dynamically change the navbar is contained within. As you can see below, they are setting the variable globally, though not always the best way, and then creating a function expression, this has to do with hoisting, and then simply hide the navigation bar. Please let me know if you need any further assistance to help you understand this.
js.file
var prevScrollpos = window.pageYOffset;
window.onscroll = function() {
var currentScrollPos = window.pageYOffset;
if (prevScrollpos > currentScrollPos) {
document.getElementById("navbar").style.top = "0";
} else {
document.getElementById("navbar").style.top = "-50px";
}
prevScrollpos = currentScrollPos;
}

Browser image render break css inline-block layout

I have 2 div with 50% width and inline-block, on this div have a image. I'm expected 2 div will stay in one line, but sometime, browser break the layout.
Here is html :
<div class="views-field views-field-title">
<span class="field-content">
<div class="field_home_team-wraper"><h2>Arsenal</h2><img src="/sites/default/files/styles/logo_150x150/public/2016-12/team_logo-2000x2000.png?itok=L_wkCsC6" width="150" height="150" alt="Arsenal logo" typeof="Image" class="image-style-logo-150x150"></div><div class="versus-wraper">v</div><div class="field_away_team-wraper"><h2>West Brom</h2><img src="/sites/default/files/styles/logo_150x150/public/2016-12/West_Bromwich_Albion.png?itok=vZlNXq8J" width="150" height="150" alt="West Bromwich Albion logo" typeof="Image" class="image-style-logo-150x150"></div>
</span>
</div>
Here is css :
div.view-id-current_match_of_the_day div.views-field-title {
position: relative;
margin-bottom: 5px;
}
.view-id-current_match_of_the_day div.field_home_team-wraper, .view-id-current_match_of_the_day div.field_away_team-wraper {
width: 50%;
padding-bottom: 1.5em;
}
.view-id-current_match_of_the_day div.field_home_team-wraper, .view-id-current_match_of_the_day div.field_away_team-wraper {
display: inline-block;
position: relative;
}
.view-id-current_match_of_the_day div.field_home_team-wraper img, .view-id-current_match_of_the_day div.field_away_team-wraper img {
width: 40%;
}
.view-id-current_match_of_the_day div.versus-wraper {
width: 10%;
position: absolute;
bottom: 0;
right: 0;
left: 0;
margin: 0 auto;
}
As i say, I'm expected 2 div will stay in one line, like this :
But it not render correctly.
When first load, layout break to 2 lines like this:
Chrome on PC (resize windows width less than 1024px for mobile responsive) and Chromme on IOS/Android have this problem, Safari on IOS have this problem too.
Firefox, Edge on PC not have problem.
When click on homepage button or click something then go back to homepage, layout become render very good.
So i realize, at the first load (or refresh load), when browser requesting image to server, server not finished respone, browser already finished render the page, when image load finish, browser make a broken layout.
When second load (click on home page again), browser get the image from local cache, layout render is just good, correctly!
I record video here :
Chrome on PC (at 30 seconds, i press Ctrl+F5 for ignore cache reload) : https://streamable.com/8xpdx
Chrome on IOS : https://streamable.com/3bu5y
I can fix this if i add float:left to div.field_home_team-wraper and and div.field_away_team-wraper, but i need to avoid float in my css.
Another fix is remove div.versus-wraper, but i need this div and this div have absolute position, so it not in the line.
I aleady know there a space between 2 inline-block elements, so i removed space in my html : How to remove the space between inline-block elements?
I don't know what wrong here, please help.
My god, i solved this problem, just move div.versus-wraper to the last of span.field-content, everything become good.
But still don't know why it make a problem, still a mysterious with me. There are something to learn, if someone know, please answer.

Use Only CSS to Alter Various Elements

I have a page with a left sidebar that I want to be able to toggle on or off based on whether or not the user clicks it. Unfortunately entering JavaScript code on this website has been disabled and I only have access to CSS.
The left sidebar has
its main div (parentBlock)
a div for the show/hide, (toggleBlock)
a div for the logo, (div1)
a div for the navbar, and (div2)
a div for social icons (div2)
When the user clicks on "Show / Hide" I want to:
Hide (display:none) the logo, navbar, and social div's, and
Set the height of the main div to something smaller (say 30px).
Is there any way to do this in CSS?
<div class="parentBlock">
<div class="toggleBlock">Show / Hide</div>
<div class="divBlah">div1</div>
<div class="divBlah">div2</div>
<div class="divBlah">div3</div>
</div>
Then if the user clicks "Show / Hide" again, it will unhide the div's and set the height back to filling the screen.
Is this possible?
I found some code that would work if the "Show / Hide" button was in "parentBlock" but it didn't work if it was within "toggleBlock" (and I have to have the Show/Hide button in toggleBlock)
(http://tympanus.net/codrops/2012/12/17/css-click-events/)
I realize onClick events require JavaScript. Those are not possible since I can't use JavaScript :( Some people try to get around it by using either :active or creating checkboxes and having the checkbox:clicked value load the action ... but it only works with certain relations that I can't seem to nail down.
Unfortunately I cannot alter the ultimate structure of "toggleBlock", div1, div2, and div3 ... only what's in them and their CSS. Also making it even more difficult is that the website randomly generates ID="" each time the page loads so the TARGET method isn't possible. Also, the 3 div's (div1 thru div3) have the same class name. I'm beginning to think it's impossible :(
(For reference, I'm trying to use the tools on the New SmugMug and they're rather restrictive)
Here is a CSS only solution using target
DEMO http://jsfiddle.net/kevinPHPkevin/r4AQd/
.button {
display: block;
width:60px;
background: red;
z-index:1;
}
#element {
display: none;
background:#fff;
margin-top:-20px;
z-index:2;
}
#element:target {
display: block;
}
#show:target {
display: block;
}
#hide {
background: #000;
color: #fff;
}
As Joum has pointed out this is not possible to do via click events but using hover on siblings you might be able to achieve a similar effect. for example try adding this css:
div.toggleBlock { display: block; }
div.toggleBlock ~ div { display: none; }
div.toggleBlock:hover ~ div { display: block; }
for more information see this: http://css-tricks.com/child-and-sibling-selectors/