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

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>

Related

Building a 'more' mobile responsive menu

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/

CSS Overwrite issue

I have a CSS-overwriting issue. There is a parent selector for a whole div which sets the styling for all inputs within. I have some inputs in it which I do want to have another styling for. Even though I put these stylings below the parents in the CSS-file, they still can not overwrite the parents css. Please see embedded CSS for further explanation. (I prefer to not use !important).
The CSS that gets applied (defined at the top of CSS-file)
#content #newPost .inner .inputs button {
width: 70%;
height: 50px;
background-color: #F7F9FA;
text-align: center;
margin: 15px 0 0 15%;
cursor: pointer;
border: 1px solid #A0A0A0;
transition: 0.2s;
}
The CSS that should get applied (defined at bottom)
#resultArray .team button {
width: 40px;
height: 100%;
border: none;
background-color: #E3E8E8;
color: #000;
padding: 0;
text-align: center;
margin: 0;
cursor: default;
}
HTML
<div id='newPost'>
<div class='inner'>
<div class='inputs'>
<div id='resultArray'>
<div class='current'><button disabled>1</button><input>
</div>
</div>
<input placeholder='Title'>
<textarea placeholder='Content'></textarea>
<button id='publishPost'>Publish</button>
</div>
So far I got from your CSS and markup code problem is chaining in CSS selection. You can try apply following selector:
#content #newPost .inner .inputs #resultArray button {
width: 40px;
height: 100%;
border: none;
background-color: #E3E8E8;
color: #000;
padding: 0;
text-align: center;
margin: 0;
cursor: default;
}
Also when you try to override long chain CSS selector you should understand properly CSS Selection Precedence rules.
How long is CSS selection chain it's dose not matter if you uderstand following precedence:
In CSS slection every selector have a mathamatical value: each tag = 1, each .class = 10 or pseudo class such as :hover, :active = 10, #id = 100, inline styling = 1000 and for !important = infinity. You can't never override one !important without another !important.
So form your first selection is "#content #newPost .inner .inputs button" = 100 + 100 + 10 + 10 + 1 = 221
But for "#resultArray .team button" = 100 + 10 + 1 = 111
So second selection will never precedence over first selection.
Also for better understanding see here.
you have extra close this div
<div id='resultArray'>
<div class='current'><button disabled>1</button><input>
</div>
</div>
remove this one and
justify you code like:
<div class='inputs'>
<div id='resultArray'>
<div class='current'><button disabled>1</button><input>
</div>
<div class='int'>
<input placeholder='Title'>
</div>
<div class='int'>
<textarea placeholder='Content'></textarea>
</div>
<button id='publishPost'>Publish</button> -->
</div>
than start work : https://jsfiddle.net/yhsLvc7g/1/
edit: wait... also there is no .team class in your html, so that selector points nowhere
--
Your first selector is WAY more specific than the bottom one, so it will be applied despite being above in the cascade flow.
You need to beat the specificity of the 2 ids, 2 classes and 1 tag of the top selector. That's A LOT of specificity, which means you need to use at least 2 ids + at least 2 classes + at least 1 tag to beat it, then the cascade will take over. Setting an additional class (so 2 + 3 + 1) or an additional ID (so 3 + 2 + 1) will beat it too.
So you need to do something ridiculous like
#content #newPost .inner .inputs #resultArray .team button
That being said, your CSS is extremely overqualified, which means you'll encounter issues like these by the millions.
What you should really be doing is changing the first selector (and all those that you have in such fashion) for less specificity, something like
.inner .inputs button
will probably do the trick
Here's a good resource to understanding CSS specificity:

Is it possible to style an html element, so that it won't 'hurt' inner styles

I'm building some sort of framework where the content of the page can be edited with ContentTools. A requirement of ContentTools is that the regions must be parents.
If you try this:
<h1 data-editable data-name="heading">Content</h1>
It wont work as a region has to contain editable block level elements. A way around this is to wrap the tag like so:
<div data-editable data-name="heading">
<h1>Content</h1>
</div>
But I just want to make the text editable, so I automatically wrapped the inner elements in a div. This works but it affects the styles.
Is there a way to make a div 'transparent', so it will inherit all styles?
I tried the following code.
To be clear: In this example I don't write the h1 css, so i have no influence over which styles are used.
$("[data-editable]").wrapInner("<div class='innerWrap'></div>");
/* example h1 css, could be anything */
body > h1{
font-size: 40px;
color: red;
font-family: sans-serif;
border: 3px solid green;
background-color: blue;
padding: 5px;
}
.innerWrap{
all: inherit;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h1 data-editable data-name="heading">Content</h1>
As you can see some things work. But things like a border will double.
It has to be no difference with or without the innerWrap.
Is it possible to do this with css? It has to work on every css property.
I think you need to wrap the h1 with a div not div with h1.
for eg. .wrapInner() will produce something like
<h1 data-editable="" data-name="heading">
<div class="innerWrap">Content</div>
</h1>
But what you want is
<div data-editable data-name="heading">
<h1>Content</h1>
</div>
So please try with .wrap() instead of .wrapInner()
$("[data-editable]").wrap("<div class='innerWrap'></div>");
h1{
font-size: 40px;
color: red;
font-family: sans-serif;
border: 3px solid green;
background-color: blue;
padding: 5px;
}
.innerWrap{
all: inherit;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h1 data-editable data-name="heading">Content</h1>
.innerWrap{
all: inherit; /* remove it*/
}
As a default behaviour, if you not specify css props for ".innerWrap" it will look same as parent only
The ability to make an individual element editable standalone as opposed to as part of a collection (e.g in a region) is currently being worked on: https://github.com/GetmeUK/ContentTools/issues/79
There is however a short-term imperfect approach you could try, first change you're HTML as follows:
<h1 data-editable data-name="heading">
<span data-inline data-ce-tag="h1">Content</span>
</h1>
This will make the h1 tag the region and tell ContentTools/Edit to treat the inner span element as a h1 (text) element (thanks to the data-ce-tag).
But the next problem is that if the user hit's return you'll end up with a new paragraph tag inside of your h1 - which we don't want. This is where the data-inline attribute comes in, we need to listen for mount events and if the element mounted has the data-inline attribute we'll modify its behaviour so it can't do certain things which might produce undesirable events:
ContentEdit.Root.get().bind('mount', function(elem) {
// We're only interested in elements that are marked as inline
if (elem.attr('data-inline') === undefined) {
return;
}
// Change the default behaviour of the element
elem.can('drag', false);
elem.can('drop', false);
elem.can('remove', false);
elem.can('spawn', false);
});
You can find out more about modifying behaviours here, along with their current limitations here.

CSS: Prevent parent element getting :active pseudoclass when child element is clicked

JSFiddle
When you click the button, you see that :active pseudoclass is triggered for the parent div. Is there a pure CSS (or some JS library) way of :active pseudoclass not toggling on button click?
I tried z-index, position: absolute & fixed and no success.
From the spec:
Selectors doesn't define if the parent of an element that is ‘:active’ or ‘:hover’ is also in that state.
That means it's implementation dependent. If an implementation chose to act this way (as current browsers obviously do), there's nothing in the standard that can change that.
With CSS4, you might be able to do:
.parent:active:not(:has(:active)) {
color: red;
}
but that is neither available nor finalized yet.
If you really want to solve this with CSS only:
If your button is active, add a :before-pseudo-element and with position: absolute; give the :before the same background as the parents.
button:active::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #eee;
z-index: -1;
}
Now all that is needed is that the parent is :
position: relative;
z-index: 0;
Have a look: http://jsfiddle.net/s0at4w4b/4/
This does not solve the underlying issue, but is a solution for your current problem.
I don't think :has pseudo-class will ever be available in stylesheets. If browsers finally decide to implement it, it will probably be only for JS APIs like querySelector.
However, I have much more hopes for :focus-within, which seems much simpler to implement.
#parent:active:not(:focus-within) {
background-color: red;
}
Of course, it will only prevent :active from being applied to #parent when clicking a focusable element like a button. You can make other elements focusable by adding tabindex = "-1"
Sadly, :focus-within is not widely supported, but you can use a JS polyfill.
#parent {
border: 1px solid black;
width: 300px;
height: 300px;
}
#parent:active:not(.focus-within) {
background-color: red;
}
<script src="https://gist.githubusercontent.com/aFarkas/a7e0d85450f323d5e164/raw/"></script>
<div id="parent">
<button>Click me</button>
<p tabindex="-1">Or me</p>
</div>
Github does not allow hotlinking, so the snippet above might not work unless you copy the polyfill to your server and use it.
Perhaps the simplest way of achieving what you probably really want to do is to put not put the button inside the div you don't want activated.
Here, you have a container div, which contains a background div (the equivalent of the parent div in your original example). The background div has an active state separate from the button's.
.container {
position: relative;
width: 200px;
height: 200px;
}
.background {
position: absolute;
width: 100%;
height: 100%;
border: 1px solid black;
background-color: #eee;
}
.background:active {
background-color: red;
}
button {
position: relative;
}
<div class="container">
<div class="background"></div>
<button>Click me!</button>
</div>
This may or may not work for you, but this is how I achieve it with pure CSS. The only caveat is the dependence of focus-within which isn't supported by IE or Edge.
.parent {
transition: background-color;
}
.parent:active:not(:focus-within) {
background-color: red;
transition-delay: 1ms; // Delay one cycle to allow child to focus
}
What's going on here is, the parent element will get the active state, as will the child that gets clicked. The only difference is that the focus will apply to the child element, but only on the next cycle. To circumvent any animations from while in this 2 step process, apply a 1ms delay. The next cycle, the element will be active, but the focus will be applied to the child. Thus, the parent will not apply the transition. I would imagine animation delay: 1ms would work the same way.
Another alternative is to give the item a tabindex=-1 attribute and use
.parent {
transition: background-color;
}
.parent:active:focus {
background-color: red;
}
The only issue with this is the fact it may change keyboard navigation behavior and relies on some HTML as well. If you do want keyboard navigation use tabindex=0 or any value besides -1. But there's no JS used.
There are some nice polyfills for focus-within that you can use for IE/Edge but that would go outside "CSS Only".
But, we can put both of them together to create this:
.parent {
transition: background-color;
}
.parent[tabindex]:active:focus {
background-color: red;
}
.parent:active:not(:focus):not(:focus-within) {
background-color: red;
transition-delay: 1ms;
}
This works on IE11, Edge, and Chrome.
http://jsfiddle.net/s0at4w4b/42/
here's a jquery solution instead of using the css pseudo class :active
$(document).ready(function() {
$('button').mousedown(function(e){
e.stopPropagation();
console.log('i got clicked');
});
$('div').mousedown(function(e){
$('div').css('background', 'red')
}).mouseup(function(e){
$('div').css('background', '#eee')
});
$(document).mouseup(function(e){
$('div').css('background', '#eee')
});
});
div {
width: 200px;
height: 200px;
background-color: #eee;
border: 1px solid black;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<button>Qlick me</button>
</div>
As far as I know, the the active state will bubble up. So all parent nodes will have an active state.
Therefore, I don't now of a pure CSS solution. You can avoid a javascript solution (which I assume is what you're really after), by altering the markup so that the div that has an active state is no longer a parent of the button. You can make them siblings, for example.
The CSS part of that solution is then fixing the layout so it appears the same now that they are sibilings as what it did when they were parent>child.
Without seeing a fiddle of what you're working with, I can't offer you a more specific solution I'm afraid.
try this
html:
<div class="current" id="current">
<button id="btnclick" >Qlick me</button>
</div>
css script:
div {
width: 200px;
height: 200px;
background-color: #eee;
border: 1px solid black;
}
.current_active{
background-color: red;
}
jquery:
$("#btnclick").click(function(){
$("#current").toggleClass("current_active");
});
JSFiddle
ps: include the jquery library file
The :active pseudo-class applies while an element is being activated by the user. For example, between the times the user presses the mouse button and releases it. On systems with more than one mouse button, :active applies only to the primary or primary activation button (typically the "left" mouse button), and any aliases thereof.
There may be document language or implementation specific limits on which elements can become :active. For example, [HTML5] defines a list of activatable elements.
The parent of an element that matches :active also matches :active.
So there,s no way
Instead of div:active {...} you should code div:active:not(:hover) {...} and the background-color stays untouched.
(old snippet removed)
UPDATE
To keep the main div behaviour intact and a more generic approach I usually create several layers.
Check the snippet below, toggling to green is just to prove that it works while position and abolute are just quick and dirty for now:
#layer-data {
width: 200px;
height: 200px;
background-color: #eee;
border: 1px solid black;
}
#layer-data:active {
background-color: red
}
#layer-btns:active {
background-color: green
}
#layer-btns {
z-index: 1;
position: absolute;
top: 1px;
left: 1px;
background: transparent;
padding: 5px;
width: auto;
height: auto
}
#layer-data {
z-index: 0;
position: absolute;
top: 0;
left: 0;
text-align: center;
line-height: 200px
}
<div id="layer-btns">
<button>Qlick me</button>
<br/>
<button>Qlick me too</button>
<br/>
<button>Qlick me three</button>
</div>
<div id="layer-data">
some data-layer
</div>
There doesn't seem to any CSS way to handle this case. (not sure about CSS4, the way Amit has suggested.) So here is JQuery way.
The idea is you handle mousedown and mouseup events at 3 levels:
the parent div
the button where you don't want the active state propagated to parent div (".btn1" in the example below)
any other children except the button in second condition. (".btn2" in the example below)
JS Fiddle
HTML:
<div>
<button class="btn1">Qlick me1</button>
<button class="btn2">Qlick me2</button>
</div>
JQuery:
$(function(){
$('div').each(function(e){
$(this).mousedown(function(e){
$(this).addClass("activeClass");
}).mouseup(function(e){
$(this).removeClass("activeClass");
});
});
$('div .btn1').each(function(e){
$(this).mousedown(function(e){
e.stopPropagation();
}).mouseup(function(e){
e.stopPropagation();
});
});
$('div :not(.btn1)').each(function(e){
$(this).mousedown(function(e){
$(this).parent().addClass("activeClass");
}).mouseup(function(e){
$(this).parent().removeClass("activeClass");
});
});
});
CSS:
div {
width: 200px;
height: 200px;
background-color: #eee;
border: 1px solid black;
}
.activeClass {
background-color: red;
}
CSS pseudo-elements are incredibly useful -- they allow us to create CSS triangles for tooltips and perform a number of other simple tasks while preventing the need for additional HTML elements. To this point, these pseudo-element CSS properties have been unreachable by JavaScript but now there's a method for getting them!
Check this:
http://davidwalsh.name/pseudo-element
http://davidwalsh.name/ways-css-javascript-interact

Is it possible to show a div on click using the :active selector in CSS?

I'm looking to show a div on click. The goal is to use pure CSS only, no jQuery.
Working FIDDLE Demo
Consider that you want something like this:
We write our markup as simple as possible. One element for container, one element for our link and one another element for popup:
<!-- [container] -->
<div class="link-with-popup">
<!-- link -->
<div class="link">CSS</div>
<!-- [popup] -->
<div class="popup">
<div class="box">CSS Description</div>
</div>
<!-- [/popup] -->
</div>
<!-- [/container] -->
Here is our layer structure in picture:
CONTAINER
Let's write CSS for our container.
.link-with-popup {
/* for visualizing */
background: yellow;
/* we need relative, because childs are absolute */
position: relative;
margin-bottom: 10px;
height: 30px;
width: 400px;
}
[!] Note that we make our container relative. Because the children will be in absolute mode.
LINK
We create our link as an absolute element from left, just as shown in the figure above.
.link {
background: blue;
position: absolute;
top: 0;
left: 0;
bottom: 0;
width: 100px;
z-index: 10;
}
POPUP
The dimention of popup element is same as the container, so we set all top, left, right, bottom properties to 0.
.popup {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: green;
z-index: 20;
}
[!] Note that z-index of popup element must be greater than link element.
.popup {
/* we won't show the popup yet */
display: none;
}
By now, we'll get this result (check it on jsFiddle):
Now we want the click for our link. This must be done with :active pseudo selector in CSS. But how we must show the poup? We have to get the next sibling element by the link. We use the + selector in CSS:
.link:active + .popup {
display: block;
}
See the result on jsFiddle. But the problem is that when user realize the mouse, the popup will disappear (as it display is set to none).
So we set the :hover rule for the popup and make it block.
.popup:hover {
display: block;
}
Check the jsFiddle demo. Now we get close enough. The only issue that the popup element, hide our link.
But it doesn't matter, because we won't set background for our popup (it will be transparent).
TEXT
For wanted text in popup element, we set this rules:
.popup .box {
position: absolute;
/* note that we make a gap from left to don't hide the link */
left: 130px;
top: 0;
right: 0;
bottom: 0;
background: #505050;
}
Check the jsFiddle demo. Now we have all things that we need.
Now it's time to make our popup element transparent (by setting the background as transparent or simply remove the background: green; rule):
.popup {
background: transparent;
}
And here is the final jsFiddle result. And if you add some extra CSS to it, it can be more stylish. Something like this that I've created.
Some important note to memorize:
In the final result, there is a gap between the link (blue one) and the popup (gray one). But the fact is that the gray element is not our popup. It's a child of popup and our popup is an 100% width and height element on the container.
Working FIDDLE Demo
Another way is to use the :target property (only works in moderns browsers).
Here's a qucik DEMO where I've hidden the div by applying opacity: 0; and the when you click the link the div changes to opacity: 1; The link and the div are matched using a hash in the url.
Here's the code from my example.
HTML
Click me
<br />
<div id="pop"></div>
CSS
#pop {
width: 100px;
height: 100px;
background: #000;
opacity: 0;
}
#pop:target {
opacity: 1;
}
There are some side effects though. The browser will jump/scroll down (not sure if it's possible to prevent this?) to the matched div and since we are using a hash in the url it will effect the browser history and, as mentioned above, it only works in modern browsers.
EDIT If you want to look into other hack/tricks for pure CSS click events, this is a good post - http://tympanus.net/codrops/2012/12/17/css-click-events/