I would like to achieve the effect of a scrolling line beneath anchor links to meet a client brief - I stupidly imagined a bit of CSS3 would easily achieve this without any bother, so I've setup something along the lines of the following code, and spent the past hour banging my head on the desk due to a very annoying bug I don't understand.
Everything works great on desktop, but on mobile (both iOS and Android) I experience an issue when I select a link - First click, the animation runs, and I have to click a second time to trigger the link (same happens with below codepen). It's baffling me and I wonder if anyone can shine any light on things for me!!?
http://codepen.io/pablodancer/pen/ZLJVOP
li {
display: inline-block;
list-style-type: none;
}
li a {
text-decoration: none;
position: relative;
line-height: 1;
height: auto;
padding: 0;
margin-right: 8px;
padding-bottom: 8px;
z-index: 1;
}
li a:after {
display: block;
left: 0;
bottom: 0;
margin-top: 4px;
width: 0;
height: 5px;
background-color: blue;
content: "";
z-index: -3;
transition: width 0.3s;
}
li a:hover:after,
li.active a:after {
width: 100%;
}
<ul>
<li class="active">nme</li>
<li>bbc</li>
<li>blah3</li>
<li>blah4</li>
<li>blah5</li>
</ul>
I believe the double tap issue is only related to iOS. What I normally do is to simply hide the pseudo element on touch devices, either approach below will work.
(1) Using CSS media queries, it works in iOS 9+ and Android 5+.
#media (hover: none) {
li a:after {
display: none;
}
}
(2) Using a bit of Javascript + CSS:
(function(html) {
html.className += ('ontouchstart' in window) ? ' touch ' : ' no-touch ';
})(document.documentElement);
.touch li a:after {
display: none;
}
In addition, if you wish to keep the active style, you can use selector li:not(.active) a:after. You may also want to set li {vertical-align: top;} so the items can lineup nicely.
This is caused by a non-standard behavior adopted by WebKit on IOS.
Weird (but common) issue needs a weird (and simple) hack, here is how I solved it with only CSS and bullet-proof browser support.
Basically, the magic is using transforms and IOS/WebKit will not consider as hidden the pseudo element, so it will not force the double-tap behavior when it's shown on hover:
li a:after {
/* keep the element 'visible' and with a size */
display: block;
content: '';
width: 100%;
height: 2px;
...
/* then 'hide' it with a transform */
transform: scaleX(0);
...
/* add a nice transition */
transition: transform 600ms ease;
}
li a:hover:after {
/* 'show' the element by resetting the transform */
transform: scaleX(1);
}
Till now, it seems to do the trick, why? because the size of a transformed element is not computed in the reflow of the page :)
Related
Is there an easy way to remove an ::after pseudo element inside of a media query?
For example can I completely remove this ::after pseudo element when the browser width falls below 980px? Or should I do it the old fashioned way and hide the original class and display a new class when the browser width shrinks below 980px? How would a professional solve this?
.navigation_unit > a::after {
content: "";
position: absolute;
box-sizing: border-box;
width: 100%;
height: .0625rem;
bottom: 0;
left: 0;
background-color: rgb(0,0,238);
transform: scaleX(0);
transition: all 0.3s ease-in-out 0s;
}
The easiest option is to set the pseudo element's content property value to none inside of the media query. In doing so, the pseudo element won't be rendered.
#media (max-width: 600px) {
.navigation_unit > a::after {
content: none;
}
}
As stated by the relevant specification, the values none or normal would result in the pseudo element no being generated.
12.2 The 'content' property
none - The pseudo-element is not generated.
normal - Computes to none for the :before and :after pseudo-elements.
Here is a basic example demonstrating this:
p::before {
content: 'Psuedo-element... ';
color: #f00;
}
#media (max-width: 600px) {
p::before {
content: none;
}
}
<p>Resize this window to less than 600px</p>
Easy enough mobile-first solution:
.navigation_unit a:after {
...
/* everything except content: '' */
}
#media (min-width:980px) {
.navigation_unit > a:after {
content: '';
}
}
I am working on this page: link to page.
Inside h2 I have before and after elements. In IE they are too big, original width and height these images are not working. When I am trying to resolve this problem, in FF and Chrome everything is getting even worse.
In Edge things are a little bit different - I have figured out a way to make images smaller, but before element is inside h2 text.
Here are the examples:
Normal (from FF and Chrome)
A little strange (from Edge)
So crazy (from IE)
CSS code:
h2{/*How I am displaying h2 elem */
text-align: center;
width: 80%;
margin: 45px auto 115px !important;
text-transform: uppercase;
color: #fff;
}
h2::before {
content: url(img/pepper.svg);
margin-right: 10px;
position: relative;
height: 50px;
}
h2::after{
content: url(img/apple.svg);
margin-left: 10px;
position: relative;
height: 50px;
}
#supports (-ms-accelerator:true) { /*Trying to resolve problem in Edge */
h2::before {
position: absolute;
}
h2::after{
position: absolute;
}
}
Try making the positon of before and after leftmost and rightmost.
If it doesnt work,try making pixels to %.
As #ankit says, removing width: 80% is doing right on IE. Also removing part with supports resolved problem with Edge.
Another approach (assuming you have control of the HTML): add an empty right after the input, and target that in CSS using input+ span:after
.field_with_errors {
display: inline;
color: red;
}
.field_with_errors input+span:after {
content: "*"
}
<div class="field_with_errors">Label:</div>
<div class="field_with_errors">
<input type="text" /><span></span>
</div>
I'm using this approach in AngularJS because it will add .ng-invalid classes automatically to form elements, and to the form, but not to the .
I am trying to create a multi-tiered menu with a breadcrumb navigation, without using javascript. I have come across loads of pure css menus and breadcrumbs, but never combined and working together. Here’s a design of what I’m trying to achieve (click on the ‘more’ hamburger menu):
https://invis.io/857RUKE6M
And this is what I have so far in my html/css (see codepen link below). Please forgive the crude/hacky code. At this point I am simply testing ideas, I will simplify and beautify my code once I’ve found a solution.
http://codepen.io/jessbenz/pen/LZWjjz
Here's a code snippet, but please look at the codepen link above to get a better feel:
<div class="smart-nav">
<input type="radio" id="bread-home" class="breadcrumb" name="bread" />
<input type="radio" id="bread-women" class="breadcrumb" name="bread" />
<input type="radio" id="bread-womens-clothing" class="breadcrumb" name="bread" />
<div class="smart-nav-panels">
<ul id="home">
<li>
<input type="radio" name="first">
<label>1 Women</label>
<ul id="women">
<li>
<input type="radio" name="second">
<label>1.1 Women's Clothing</label>
<ul id="womens-clothing">
<li>
<label>1.1.1 Women's Shirts</label>
</li>
</ul>
</li>
</ul>
</li>
<li>
<input type="radio" name="first">
<label>2 Men</label>
<ul id="men">
<li>2.1 Men's Shirts</li>
</ul>
</li>
</ul>
</div>
</div>
and my sass:
.breadcrumb:checked ~ .smart-nav-panels ul {
display: none;
}
#bread-home:checked ~ .smart-nav-panels > ul {
display: block;
}
#bread-women:checked ~ .smart-nav-panels {
#home, #women {
display: block;
}
}
#bread-womens-clothing:checked ~ .smart-nav-panels {
#home, #women, #womens-clothing {
display: block;
}
}
#bread-home:checked ~ .smart-nav-panels li input:checked > ul:first-child {
display: block;
}
.smart-nav-panels {
margin: 0;
padding: 0;
ul {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 100%;
height: 100%;
background: lightgrey;
}
ul, li {
list-style: none;
margin: 0;
padding: 0;
}
> ul:first-child {
ul {
left: 100%;
}
}
li {
input + label + ul {
display: none;
}
input:checked + label + ul {
display: block;
// left:0;
}
}
}
input:checked ul {
display: block;
}
If you click through the women's clothing in my codepen sample, you’ll see I am half way there with achieving what I need. The top horizontal radio buttons represent the breadcrumbs and vertical radio buttons within the gray block represent the tier menu. The problem comes in when I select a breadcrumb radio. The correct slide is displayed but then if I select a radio within the menu again, it isn’t displaying because my breadcrumb css is taking preference and hiding the relevant content. I guess herein lies the issue with not using javascript. How do I make both my navigations aware of each other with pure css? It could be that this approach of combining two radio navigations is the incorrect one. I really hope someone can share their wisdom. :)
Thanks in advance
You don't shy away from a challenge, do you? :)
Before I launch into any more detail, I would say that the short answer is "build a static site". In other words, assuming one of your design constraints is "no javascript", move the problem to a place where you do have the luxury of using decision logic / code to make it easier to solve (ie: the server).
Even if you manage to solve this problem (and I'm not sure it's possible given the constraints of HTML/CSS), the next problem you're going to have is attaching any sort of behaviour to it all. You're going to want to load specific content based on the menu selection, and the only way you're going to do that is with:
a javascript event, or
a static link (anchor element, hence the 'why' behind my short answer)
One could load all of the content and perhaps find a way to display it conditionally, but then the question is "how deep does the rabbit hole go?". Plus if you're building for feature phones and/or slow connections, loading all of the content is going to have a negative impact on the user experience.
Having said all of that, I managed to simplify the CSS slightly and fix a bug with the display of subcategories (see comments inline). Note that only the 'Women' category behaves as expected as there are styles missing for 'Men' & 'Kids'.
.container {
position: relative;
width: 360px;
height: 480px;
border: 1px solid black;
margin: 20px auto 0 auto;
}
.breadcrumb {
margin-top: -20px;
display: inline-block;
vertical-align: top;
}
/*
.breadcrumb:checked ~ .smart-nav-panels ul {
display: none;
}
#bread-home:checked ~ .smart-nav-panels > ul {
display: block;
}
*/
/* hide all uls except the 'home' ul by default, replaces both of the above */
.smart-nav-panels ul ul {
display: none;
}
/*
#bread-women:checked ~ .smart-nav-panels {
#home, #women {
display: block;
}
}
#bread-womens-clothing:checked ~ .smart-nav-panels {
#home, #women, #womens-clothing {
display: block;
}
}
*/
/* these next 3 style definitions are very similar to what you had before (commented
above), except that there is no longer a need to unhide the 'home' ul, and we're
being more explicit about which uls to hide in correspondence with the state of the
breadcrumb nav */
#bread-home:checked ~ .smart-nav-panels {
#women {
display: none;
}
}
#bread-women:checked ~ .smart-nav-panels {
#women {
display: block;
}
#womens-clothing, #womens-shoes {
display: none;
}
}
#bread-womens-clothing:checked ~ .smart-nav-panels {
#women, #womens-clothing {
display: block;
}
}
/*
#bread-home:checked ~ .smart-nav-panels li input:checked > ul:first-child {
display: block;
}
*/
/* (i) the above didn't work because the ul isn't a direct descendant of the input,
rather it is a sibling, and in addition it doesn't matter which breadcrumb item is
checked now */
.smart-nav-panels li input:checked ~ ul {
display: block;
}
.smart-nav-panels {
margin: 0;
padding: 0;
ul {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 100%;
height: 100%;
background: lightgrey;
}
ul, li {
list-style: none;
margin: 0;
padding: 0;
}
> ul:first-child {
ul {
left: 100%;
}
}
/* removed unnecessary styles here */
}
/* removed unnecessary style here */
This has solved some of the problems, but there are still many more. Solving some of them will, I suspect, create new ones. One immediate one I can think of is that you'll want to tie the state of the tiered menu to the breadcrumb in such a way that you only see as much of the breadcrumb as you're supposed to (right now you always see all of it).
At some point you're going to want events (for behaviour) and components will need to know about each other's state. While CSS has some state capabilities it provides nothing on the event front. These limitations, the cascading nature (discussed in depth in other questions, eg: lack of ancestor selector) and coupling to the HTML structure all contribute to make this a very hard problem to solve with HTML & CSS alone.
I understand the desire to have this type of navigation without JS and certainly this is an interesting problem to try and solve, but ultimately I think it's the wrong way to go about it.
There is a reason why javascript is so ubiquitous - our experience of the web as it is today simply wouldn't be the same without it.
(Thanks to Jess and other colleagues for the discussion that informed parts of this answer. I paraphrased liberally. Hopefully this is of benefit to someone else.)
I have a goal that I'm trying to accomplish with HTML and CSS only: With an inline list of links that grow in size upon hover and change fonts (this has caused odd issues before),
A) Hovering one link shouldn't upset other links.
B) Keep it dynamic to avoid tailoring the CSS to each new link.
C) If margin: 0 20px 0 20px, that should be from the ends of the text -- This looks much cleaner, as it makes the spacing constant between links (see example for what should not be done). Fixed width containers usually violate this.
D) Upon hover, the text should stay vertically and horizontally centered in place.
E) Please try to keep it HTML and CSS only. If it includes JS or JQ, it would be more difficult to implement to to my lack of knowledge about the languages and the fact that the JSFiddle is just a stripped down example instead of my actual page.
My best right now fits the first two and last criteria without meeting the third, and it uses tables (I know):
JSFiddle
Or code:
<table><tr>
<td><div>ONE</div></td>
<td><div>TWO</div></td>
<td><div>THREE</div></td>
<td><div>FOUR</div></td>
<td><div>FIVE</div></td>
</tr></table>
And...
div:hover {
font-size: 130%;
font-family: comic sans ms;
}
div {
width: 10px;
margin: 0 30px 0 30px;
height: 20px;
}
The issue is that the margin is being measured from the div, not the text, making it so I'd have to tailor the margin to each link. Additionally, hovering will make it seem like the font / link moves down and to the right, violating guideline D.
This Works dynamically as long as the text isn't too long, but hovering upsets other links. It also violates D.
Any help would be appreciated.
Vertical alignment for inline text is handled easily with the line-height property. Make sure that for both the normal and large font-sizes the line height is the same. Eg. for normal text I used line-height: 1.5em, for the large text I used font-size: 130%; line-height: 1.15385em;. 1.30 × 1.15385 = 1.50
The main issue I see is that when hovering the browser needs the text in the original size for the layout, but it also needs the text in bigger size for display. One solution I see is duplicating the link text and show only one version depending on hover state:
HTML:
<ul>
<li><span>link 1</span><span>link 1</span>
<li><span>link 2, with some long text</span><span>link 2, with some long text</span>
<li><span>link 3</span><span>link 3</span>
</ul>
CSS:
ul, li {margin: 0; padding: 0;}
li { list-style-type: none; display: inline-block; line-height: 1.5em; }
li { border: 1px dotted red; position: relative; }
li a span:first-child { padding: 0 30px; }
li a span:last-child { position: absolute; width: 100%; left: 0; font-size: 130%; line-height: 1.15385em; text-align: center; visibility: hidden; }
li:hover a span:first-child { visibility: hidden; }
li:hover a span:last-child { visibility: visible; }
http://jsfiddle.net/g16Ldusx/2/
Instead of duplicating the link text in HTML, I would probably duplicate it using some javacript.
If you don't want the duplication and really don't want javascript, you can use the :before and :after pseudo-elements instead, and put the link text in a HTML5 data attribute. Not sure how good the browser support for this one is though.
HTML:
<ul>
<li>
<li>
<li>
</ul>
CSS:
ul, li {margin: 0; padding: 0;}
li { list-style-type: none; display: inline-block; line-height: 1.5em; }
li { border: 1px dotted red; position: relative; }
li a:after { content: attr(data-text); padding: 0 30px; }
li:hover a:after { visibility: hidden; }
li:hover a:before { content: attr(data-text); position: absolute; width: 100%; font-size: 130%; line-height: 1.15385em; text-align: center; }
http://jsfiddle.net/kyad4tfh/
Also, note that requirements A and C may conflict with each other. The margin between elements needs to be big enough to accomodate for the increased width of the text.
I'm working on a website on wordpress.
I have a wrapper with header and entry inside of it.
my Body height is set to height: 100%;
Wrapper is set to height: 100% and min-height: 100%.
The height of my page expand depending of the content of my entry, that works perfectly on most of pages.
but on some pages, I've included Pure CSS Tabs, which are set to position:absolute to work.
I used this example : http://www.onextrapixel.com/2013/07/31/creating-content-tabs-with-pure-css/
on pages including those tabs my content doesn't expand anymore, I can not use position:relative for the tabs...
Is there a way of expending the body height depending of my tab contact height ?
maybe using Js ?
can anybody help me ?
here is my css :
html,body{
width: 100%;
max-width: 1220px;
font-family: 'andale';
font-size:14px;
line-height: 20px;
color: black;
text-transform: none;
background-color: #4C4C4C;
letter-spacing: 2px;height: 97%;}
#wrapper{
background-color: white;
height: auto !important; /* ie6 ignores !important, so this will be overridden below */ min-height: 100%; /* ie6 ignores min-height completely */
margin-left: 20px;
margin-top: 20px;
padding-top: 20px;
height: 100%;}
.entry{
padding-left: 20px;
padding-right: 20px;}
#header{
font-size: 14px;
line-height: 20px;
width: 100%;
color: #FF5000;
text-decoration: none}
.menu-menu-container{clear: both;padding-top: 5px;}
#menu-menu {list-style:none;}
.menu-item {float:left;}
#menu-menu li:after{content:"\00a0|";}
#menu-menu li:before{content:"\00a0";}
#menu-menu li:first-child:before{content:"";}
#menu-menu li:last-child:after{content:"";}
#menu-menu li.current_page_item a { color:#FF5000;text-decoration: line-through }
#menu-menu li.current-page-ancestor a { color:#FF5000;text-decoration: line-through }
.tabs input[type=radio] {
position: absolute;
top: -9999px;
left: -9999px;
}
.tabs {
list-style: none;
position: relative;}
.tabs li{
float: left;}
.tabs li:after{
content:"|\00a0";}
.tabs li:last-child:after{
content:"";}
.tabs label:hover {
color:#FF5000;
text-decoration: line-through}
[id^=tab]:checked + label {
color:#FF5000;
text-decoration: line-through}
[id^=tab]:checked ~ [id^=tab-content] {display: block;}
.tab-content{
z-index: 2;
display: none;
text-align: left;
width: 100%;
left: 0;
position: absolute;}
here is a jsfiddle http://jsfiddle.net/MPhnP/
anyone can help me with this ? is it possible using the css tabs I'm using ?
thanks a lot for your help !
Wow, I remember battling with this exact problem a couple of months ago, I was even using those exact same tabs you linked.
The thing with absolute positioning is that you are positioning the elements outside of the normal flow of the webpage - any div with position absolute will not contribute to the page flow.
This leaves you with 2 options:
Manually set the height of the tab group. For example:
.tabs {
height: 450px;
}
I don't like this solution as it means you can't have a dynamic height for each tab - all tabs will be the same height. If your first tab had only a few lines of text and your 2nd one had many paragraphs, the whole thing would just look weird, or you would have a large gap under the tab group.
So what are your other options? Ditch pure CSS tabs and use jQuery. Honestly, I spent hours and hours researching pure CSS tabs trying to find/create some that were practical and functional, and I concluded it just isn't feasible. Pure CSS tabs are just gimmicks and a brilliant example of the power of CSS, but I do not believe they have any practical use in a production environment.
EDIT: It just occurred to me you probably CAN use JS to get your tabs to work how you want, but if you're going to go down that route, why not just use JS tabs?