Can you use a css rule as a selector? - html

Let me explain:
I have multiple items with all different width's. And when I hover them it displays captions at 50% width. BUT the captions on the images at 25% are way too small.
I want to make the captions 100% width and 100% height on the ones with 25%.
Can I specify this in my css?
List of images:
.item1 {
width:100%;
float:left;
}
.item2 {
width:25%;
margin-left:50%;
margin-right:25%;
float:left;
}
.item3 {
width:50%;
margin-right:25%;
float:left;
}
.item4 {
width:25%;
float:left;
}
.item5 {
width:50%;
margin-left:50%;
float:left;
}
.item6 {
width:50%;
margin-right: 50%;
float:left;
}
posthover = my selector
.posthover {
width:50%;
height:auto;
display:none;
#post:hover .posthover {
display:block;
It must be something like this:
.posthover (only width 25%) {
width:100%
height:100%
}
#post:hover .posthover (only width 25%) {
width:100%
height:100%
}

Specify your own width and height in pixels
.hover:hover {
width: 100px;
height: 100px;
}

So you want to set the height and width to 100% only on the items that use 25%, right?
Then declare that.
.item2 {
width:25%;
margin-left:50%;
margin-right:25%;
float:left;
}
.item2:hover {
width:100%;
}

Can you use a css rule as a selector?
No, as great as this would be, we cannot select via CSS properties.
Here are two ways to limit your selection
Using this HTML
<ul>
<li class="item1"></li>
<li class="item2"></li><!-- Select this -->
<li class="item3"></li>
<li class="item4"></li><!-- Select this as well -->
<li class="item5"></li>
<li class="item6"></li>
</ul>
#1 - Select the awesome way:
Browser Compatibility: Browser support is pretty good (IE 9 +)
If you need broader browser support, use the second, boring example.
Use nth-child:
li:hover:nth-child(2n):nth-child(-n+4) {
width:100%;
}
Let's break down the parts:
li:hover = on li hover
:nth-child(2n) = select every second li
:nth-child(-n+4) = select only from the first four lis
Become an nth master!
Awesome Example
Hover the list item blocks
* {
margin: 0;
padding: 0;
}
li {
background: #F00;
height: 100px;
transition: all 0.3s;
}
.item1 {
width: 100%;
}
.item2 {
width: 25%;
}
.item3 {
width: 50%;
}
.item4 {
width: 25%;
}
.item5 {
width: 50%;
}
.item6 {
width: 50%;
}
li:hover:nth-child(2n):nth-child(-n+4) {
width: 100%;
}
<ul>
<li class="item1"></li>
<li class="item2"></li><!-- Select this-->
<li class="item3"></li>
<li class="item4"></li><!-- Select this as well -->
<li class="item5"></li>
<li class="item6"></li>
</ul>
#2 - Select The boring way
String the class selectors together with ,
.item2:hover,
.item4:hover {
width:100%;
}
Browser Compatibility: Everywhere.
Boring Example
Hover the list item blocks
* {
margin: 0;
padding: 0;
}
li {
background: #F00;
height: 100px;
transition: all 0.3s;
}
.item1 {
width: 100%;
}
.item2 {
width: 25%;
}
.item3 {
width: 50%;
}
.item4 {
width: 25%;
}
.item5 {
width: 50%;
}
.item6 {
width: 50%;
}
.item2:hover,
.item4:hover {
width: 100%;
}
<ul>
<li class="item1"></li>
<li class="item2"></li><!-- Select this -->
<li class="item3"></li>
<li class="item4"></li><!-- Select this as well -->
<li class="item5"></li>
<li class="item6"></li>
</ul>

No, there is nothing even remotely resembling the use of a CSS rule as a selector. The same applies to what you are actually asking in the question body, namely using the value of a property (somehow) in a selector. A CSS style sheet is a collection of rules that are independent of each other; they interact only in the sense that they all (potentionally) contribute to the way in which elements are rendered.
Thus, you need to analyze how your style sheets set, say, the width of something to 25% and then use the selectors in the rules identified to set up additional rules.

Related

Nested css selectors by adding to class name in SASS

I am building a flexbox grid system and am looking to keep my scss file manageable.
What is wrong with the selectors for elements with classes col-2, col-4, col-6 that are causing them not to work?
.grid-container{
max-width:1280;
margin: 0 24px;
display: flex;
[class^="col"]{
flex:1;
margin: 0 8px;
&:first-child{
margin-left:0;
}
&:last-child{
margin-right:0;
}
[class*="-2"]{
width:16.5%;
}
[class*="-4"]{
width:33%;
}
[class*="-6"]{
width:50%;
}
}
}
All columns are getting the styling for margin and the first-child and last-child behavior but not the width from the other selectors. Is this perhaps a flexbox issue? flex-basis?
It's not a "flexbox" issue. It's a "CSS" issue.
[class^="col"] {
[class*="-2"] {
width:16.5%;
}
}
will result in this CSS:
[class^="col"] [class*="-2"]{width:16.5%;}
But you probably want...
[class^="col"][class*="-2"]{width:16.5%;}
... which would be produced by...
[class^="col"] {
&[class*="-2"] {
width:16.5%;
}
}
The space (in CSS) and the ampersand & (in SCSS) are the differences.
[class^="col"] {
[class*="-2"] {
width: 16.5%;
}
[class*="-4"] {
width: 33%;
}
[class*="-6"] {
width: 50%;
}
}
Will produce the following selectors:
[class^="col"] [class*="-2"] {}
[class^="col"] [class*="-4"] {}
[class^="col"] [class*="-6"] {}
Notice the space between each attribute selector. The selectors above will first search for and element that has a class attribute that starts with the .col class. They then find an element nested within the .col element with a class attribute that contains -2, -4 or -6 somewhere in the attribute.
By adding an ampersand & you can capture the current selector path. The following SCSS is the same as what you have now:
[class^="col"] {
& [class*="-2"] {
width: 16.5%;
}
}
Compiles to (space between attribute selectors):
[class^="col"] [class*="-2"] {}
Placing the ampersand immediately before the nested selector (like you have with first-child and last-child) gives a different result, the one you (likely) want:
[class^="col"] {
&[class*="-2"] {
width: 16.5%;
}
}
Compiles to (no space between attribute selectors):
[class^="col"][class*="-2"] {}
IMHO what you have currently is over engineered. I'd suggest something more straightforward and flexible. Use regular class selectors.
.col {
&-2 { width: 16.5%; }
&-4 { width: 33%; }
&-6 { width: 50%; }
}
[class*="col-"] {
flex: 1;
margin: 0 8px;
&:first-child { margin-left: 0; }
&:last-child { margin-right: 0; }
}
See below Stack Snippet to see what the above is compiled to. Note that I used *= (asterisk equals) instead of ^= (caret equals) for class placement flexibility. Up to you if you want to enforce column classes to be the first class in the class attribute value.
https://codepen.io/anon/pen/yXveRq
.row {
display: flex;
}
.col-2 { width: 16.5%; }
.col-4 { width: 33%; }
.col-6 { width: 50%; }
[class*="col-"] {
flex: 1;
margin: 0 8px;
}
[class*="col-"]:first-child {
margin-left: 0;
}
[class*="col-"]:last-child {
margin-right: 0;
}
<div class="row">
<div class="col-4">Col 1</div>
<div class="col-4">Col 2</div>
<div class="col-4">Col 3</div>
</div>
CoJanks.
The quick and dirt fix is to set additional definitions to the 'flex' on the .col class in the .grid-container.
Here is a quick and dirty answer to solve your problem for ya!
flex:1 1 auto;
FYI. There were some discrepancies in class nesting as well that I covered in the link provided.

Black 1px line between two elements

Is it possible to remove this vertical line between two colored elements(red and green). Whats wrong with my code? or its color shadow or what i dont understand
div {
height: 30px;
font-size: 0;
}
div li {
display: inline-flex;
height: 100%;
}
li:first-child {
width: 33.3%;
background-color: red;
}
li:nth-child(2) {
width: 33.3%;
background-color: green;
}
li:last-child {
width: 33.3%;
background-color: yellow;
}
<div>
<li></li>
<li></li>
<li></li>
</div>
The line is black because computers are "lazy" and combine colors by mediating the color value like C = (C1+C2)/2 when it should be C = ((sqr(C1) + sqrt(C2)/2)/2)^2. You understand why they are "lazy".
Watch this youtube video for more details. https://www.youtube.com/watch?v=LKnqECcg6Gw
And they combine because the browser pixels don't fit to your screens pixels.. at some point someone does some color combination.
33.3% x 3 = 99.9%
I agree with the previous comments, set 33.4% one of them.

Aligning labels at the center

I want to align 4 text labels at the center with a margin of 5px.
The Code:
.header_section span {
width: 100%;
}
.header_section min {
padding-left: 30%;
padding-right: 5%;
}
.header_section consume {
padding-right: 5%;
}
<div class="header_section">
<span class="min">Min</span>
<span class="consume">Consumption</span>
<span class="avg">Average</span>
<span class="max">Max</span>
</div>
Do I need to add an id instead of a class?
Do I need to use the label tag instead of the span tag?
<style>
.header_section{
text-align:center;
}
.header_section span {
width: 100%;
}
.header_section min {
padding-left: 30%;
padding-right: 5%;
}
.header_section consume {
padding-right: 5%;
}
</style>
Below style can do this. It adds a left-margin of 5px to all spans except the first.
.header_section{
text-align:center;
}
.header_section span + span {
margin-left:5px;
}
A bit improved version is here in this fiddle
Do I need to add an id instead of a class?
No
Do I need to use the label tag instead of the span tag?
No. Labels are for texts associated to a input in a form. Maybe is a list, depending of the semactic meaning.
.header_section{
text-align:center;
}
.header_section li{
display:inline-block;
margin-right:5px;
}
<ul class="header_section">
<li>Min</li>
<li>Consumption</li>
<li>Average</li>
<li>Max</li>
</ul>

Why doesn't float within a #media query work as expected?

EDIT: Resolved!
EDIT: Kevin's answer resolves the issue; however, it's not clear to me why the float declaration within the #media query doesn't work. Any thoughts would be appreciated--
I have two data sets which are semantically one, chronological list. On tablets and browsers, I'd like to display these lists as two separate columns. On a phone or smaller screens, I'd like to collapse the two columns into a single column preserving their chronological order. A solution which preserves the chronological ordering of the elements is an ordered list which I style to create the appearance of two columns; e.g. here is a fiddle demonstrating that solution.
Basically, I have an ordered list whose list elements have one of two classes (.left or .right) which cause them to float to the left and right, and I have a set of #media-queries which creates the responsive behavior I want. The issues is that while I can float them left and right, I don't know how to create the vertical flow I want. e.g. in that fiddle, I have a list,
<body>
<ol>
<li class='left'>Left 1 <br> Left 1 continued </li>
<li class='right'>Right 1</li>
<li class='right'>Right 2</li>
<li class='left'>Left 2</li>
</ol>
</body>
which is styled simply,
<style>
ol {
margin: 0;
padding: 0;
list-style-type: none;
}
#media (min-width: 50em) {
body {
width: 50em
}
li {
width: 45%
}
}
#media (max-width: 50em) {
li {
width: 100%;
}
.left {
float: left;
}
.right {
float: right;
}
}
li {
display: inline-block;
}
li.left {
background-color: blue;
}
li.right {
background-color: red;
}
</style>
But, with that, the content in the right column appears shifted down--as below:
instead of what I actually want, which would look something like this:
I know that I can implement this as two separate columns/divs which are re-ordered by JavaScript on a smaller screen, but I was wondering if there was a way which would preserve the semantic aspect of their ordering while avoiding the vertical flow issues here?
Thanks!
your fiddle
The problem is that those elements were not floating elements.
Giving them the float property in that particular media query simply doesn't work as you expected. Check now, it should go. Just enlarge the window of the fiddle.
Your new CSS
#media (max-width: 50em) {
li {
width: 100%;
}
}
li.left {
float:left;
background-color: blue;
}
li.right {
float:right;
background-color: red;
}
Here is quite a bit of a different attemp. Maybe it fits your need.
http://jsfiddle.net/NicoO/vyMWS/2/
your question is quite confusing, you should have not put the phrases left and right into your image, but: start story 1 + end story 1 etc.
ol
{
margin: 0;
padding: 0;
list-style-type: none;
-webkit-column-count: 2;
-moz-column-count: 2;
-ms-column-count: 2;
-o-column-count: 2;
column-count: 2;
}
ol li
{
background-color: blue;
display: block;
}
ol li:nth-child(2n)
{
background-color:red;
}
#media (max-width: 50em) {
ol
{
-webkit-column-count: 1;
-moz-column-count: 1;
-ms-column-count: 1;
-o-column-count: 1;
column-count: 1;
}
}

Building overlapping, oddly-rotated sprites

My current project involves setting up a bunch of sidebar links, such that the finished design looks like this:
The envelopes are supposed to move and overlap (i.e., change z-index), depending upon which icon/text is currently has :hover state.
I thought each would be a separate PNG file, but I've been given a sprite that looks like this:
Any suggestions how I could achieve this? Normally I'd just change the background position of the list elements each piece of text is in, but I don't think this is possible given the overlapping nature of these. Does he just need to export it differently?
Many thanks...
To me it looks like that sprite would work perfectly. The left most image is for when book is hovered, second image for twitter, third for facebook, forth for email. I'm guessing the last one is just the default state. Its tricky to make this work with pure css and :hover (but possible!), however, it would be extremely easy with javascript.
For the pure css solution, the div with the sprite would have to be the child of all the text elements, so you could change the background based on :hover on the parent (the text). If this isn't clear, I can make you some example code.
Edit:
Its not perfect, but its a proof of concept.
JsFiddle: http://jsfiddle.net/jp6fy/
CSS:
#side{
position:relitive;
height:341px;
width:250px;
}
#link1{
top:0;
}
.link{
position:absolute;
left:0;
top:85px;
height:85px;
padding-left:160px;
width:90px;
}
#image{
position:absolute;
top:-255px;
left:0;
z-index:-1;
background:url(http://i.stack.imgur.com/I2Y4k.png) -720px 0;
height:341px;
width:150px;
}
#link1:hover #image{
background-position:-540px 0;
}
#link2:hover #image{
background-position:-360px 0;
}
#link3:hover #image{
background-position:-180px 0;
}
#link4:hover #image{
background-position:-0px 0;
}
HTML:
<div id='side'>
<div class='link' id='link1'>
email
<div class='link' id='link2'>
facebook
<div class='link' id='link3'>
twitter
<div class='link' id='link4'>
book
<div id='image'></div>
</div>
</div>
</div>
</div>
</div>
It is possible. (But ugly.)
As a :hover selector can only affect elements inside (or directly adjacent) to the triggering element, the solution is to nest the trigger elements: (jsFiddle)
<style>
div {
width: 100px;
height: 100px;
position: absolute;
left: 100px;
}
#image { background: black; }
#trigger1, #trigger1:hover #image { background: red; }
#trigger2, #trigger2:hover #image { background: green; }
#trigger3, #trigger3:hover #image { background: blue; }
</style>
<div id="trigger1">
<div id="trigger2">
<div id="trigger3">
<div id="image"></div>
</div>
</div>
</div>
But preferably, you'd get the envelope sprites exported separately (you can of course still use CSS sprites). That should give you simpler HTML and CSS, a smaller image, and you'll avoid having to muck around with nested absolutely positioned elements, each having its own coordinate system.
I tried an approach which keeps the markup fairly simple, with only one extra non-semantic div per item:
<ul>
<li id="email">
<div class="background"></div>
<em>Email</em> chris
</li>
<li id="facebook">
<div class="background"></div>
<em>Facebook</em> follow us
</li>
<li id="twitter">
<div class="background"></div>
<em>Twitter</em> your life away
</li>
<li id="book">
<div class="background">
</div><em>Book</em> a project
</li>
</ul>
I positioned all the different copies of the background div at the same place, then varied the background position based on the hover states:
/* First, just style the document and the list text in general.
skip on for the important bit */
body {
background-color: black;
color: white;
}
ul {
width: 350px;
margin-top: 40px;
position: relative;
}
li {
margin-right: 40px;
font-family: "Century Gothic", Helvetica, sans-serif;
text-align: right;
margin-bottom: 0px;
padding: 15px 4px 25px 0;
}
li em {
text-transform: uppercase;
display: block;
}
li:hover {
color: red;
}
/* From here down is the important bit */
/* Set up the sprite in all the .background divs */
div.background {
background-image: url(http://i.stack.imgur.com/I2Y4k.png);
position: absolute;
top: 0;
left: 0;
height: 341px;
width: 160px;
}
/* By default, turn off the background in all the divs */
div.background {
display: none;
}
/* Just picking an arbitrary item to show the default, non-hover background */
#email div.background {
display: block;
background-position-x: -737px;
}
/* If we're hovering over the list as a whole, disable the default background,
so it doesn't show up underneath the background we want to display */
ul:hover #email div.background {
display: none;
}
/* For the email item, which shows our arbitrary default background, override
to the email background on hover with more specificity than the default rule */
ul:hover #email:hover div.background {
display: block;
background-position-x: 0px;
}
/* For all other items, override to their background on hover */
#facebook:hover div.background {
display: block;
background-position-x: -375px;
}
#twitter:hover div.background {
display: block;
background-position-x: -189px;
}
#book:hover div.background {
display: block;
background-position-x: -556px;
}
Working, though slightly rough example, in this jsFiddle.
Note that it's okay to have multiple copies of the sprite in multiple different divs; the browser will just grab one copy for its cache and use that for all instances of the image.
Could you create an image map and then hover swaps the image to the one with the correct envelope in front. See this link on an interesting link
google search link on idea
My method with clean HTML.
.nav { position: relative; }
.nav li {
margin-left: 179.8px;
list-style-type: none;
}
.nav li:before {
position: absolute;
left: 0; top: 0;
content: url(http://i.stack.imgur.com/I2Y4k.png);
clip: rect(0 899px 341px 719.2px);
margin-left: -719.2px;
z-index: 1;
}
.nav li:hover:before { z-index: 2; }
.email:hover:before {
clip: rect(0 179.8px 341px 0);
margin-left: 0;
}
.facebook:hover:before {
clip: rect(0 359.6px 341px 179.8px);
margin-left: -179.8px;
}
.twitter:hover:before {
clip: rect(0 539.4px 341px 359.6px);
margin-left: -359.6px;
}
.book:hover:before {
clip: rect(0 719.2px 341px 539.4px);
margin-left: -539.4px;
}
<ul class="nav">
<li class="email">Email</li>
<li class="facebook">Facebook</li>
<li class="twitter">Twitter</li>
<li class="book">Book</li>
</ul>