I'm working on a little design challenge, and it's getting the better of me right now.
Essentially, it's a material design card, which means when I click it it takes me somewhere else.
The easy route would be (and as it is now) is to surround the content with an anchor. However, in this case I ONLY want the anchor text to be "My keyword".
Here's the simple html output:
<a class="post-card md-card">
<div class="md-card-title aspect-16x9">
<div class="title-large"></div>
</div>
<div class="md-card-content">
<div class="sup-text"></div>
</div>
</a>
So, the 2 things I want to do are:
Only have the keyword inside the anchor
Be able click the whole thing (the link covers the entire outer div)
Here's the stuff that make it more difficult:
The blue box on top has an aspect ratio set, which means its not a
constant height
The text inside the blue box is centered using Flexbox
The white box isn't a fixed height either
Here's how the aspect ratio is calculated:
.AspectRatio(#widthRatio:16; #heightRatio:9; #useableWidth:100%) {
&:extend(.clearfix all);
overflow:hidden;
max-width:#useableWidth;
&::before {
content:"";
float:left;
padding-top:percentage(#heightRatio / #widthRatio);
}
}
So I need to keep the keyword text where it is but make the whole thing clickable.
I've been playing around with the idea an absolutely positioned anchor on top, which I can do but I can't get it to stretch to the bottom without moving the text.
Any CSS gurus got some ideas?
This should give you a good starting place...
.post-card {
background-color: #63d9ff;
box-sizing: border-box;
position: relative;
width: 200px;
}
.post-card * {
box-sizing: inherit;
}
.post-card .md-card-title {
bottom: 0;
left: 0;
position: absolute;
right: 0;
text-align: center;
top: 0;
}
.post-card .md-card-title .content-prop,
.post-card .md-card-title .content {
display: inline-block;
vertical-align: middle;
}
.post-card .md-card-title .content-prop {
padding-top: 56%;
width: 0;
}
.post-card .md-card-title .content {
padding: 1rem;
width: 100%;
}
.post-card .space-prop {
display: block;
padding-top: 56%;
}
.md-card-content {
background-color: grey;
padding: 1rem;
}
<div class="post-card md-card">
<a class="md-card-title aspect-16x9" href="#">
<span class="content-prop"></span><!--
--><span class="content">My Keyword</span>
</a>
<span class="space-prop"></span>
<div class="md-card-content">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. In quis mauris ut eros consectetur efficitur vitae at leo.
</div>
</div>
JSFiddle
So the explaination...
The whole post card is positioned relative, the anchor is then positioned absolute within it. The anchor is given a top, left, bottom, and right value of 0 which makes it cover it's parent container.
The content-prop and space-prop are given no height but have a top padding of 56%. This means that their top-padding value is 56% of their width which works out at a 16:9 ratio. The space banner is used here to add a empty gap at the top of the post card to make room for the anchor.
Both the content-prop and the content elements are set to display inline-block and vertical aligned to middle. Because the prop is taller than the content, the content floats in the centre. The HTML comment between these two elements eliminates white space so that the content div can be set to 100% width even when the prop is on the same horizontal row.
Related
I'm trying to use position: sticky on a rotated element but I get extra space at the top. Also where the sticky element has to stops (at the end of parent) it goes outside.
Notice I need to have control to choose how many pixels put between sticky element and the left window side.
Check the 2 screenshot to understand the 2 problems, and what I want to achieve.
Problem 1: extra space at top
Problem 2: sticky element goes outside at the end of section
I'm using this code:
HTML
<section class="section">
<h1 class="section__title">STICKY</h1>
<div class="container">
<div class="row">
<div class="col [ col-lg-8 offset-lg-2 ]">
<div class="h4">
Lorem ipsum dolor sit amet consectetur adipisicing elit. Ipsam quos illum aperiam officia provident, mollitia at, tempore atque, blanditiis sit optio esse harum officiis voluptas iusto sequi. Magni, reiciendis quidem.
</div>
</div>
</div>
</div>
</section>
CSS
.section__title {
display: inline-block;
transform: rotate(-90deg) translatex(-100%);
transform-origin: 0% 0%;
margin-bottom: 0;
position: sticky;
top: 0;
left: 50px;
}
Here is a Codepen with the entire code: https://codepen.io/anon/pen/KLqJGG
How can I solve this?
Thanks
Problem 1: extra space at top
The stickily positioned element stays in the DOM flow - just like a relative positioned element does. So, hence the space there, which is occupied by the h1.section__title element.
Problem 2: sticky element goes outside at the end of section
It is because, the original height of the h1 element is still considered there, even after rotation.
So, you need to determine the exact width of the sticky header (which then becomes the height of this element after rotation) first and then set this width value for the rotated element's height, as follows:
$section-sticky-header-height: 145px;
.section__title {
display: inline-block;
margin-bottom: 0;
transform-origin: 0% 0%;
position: sticky;
top: 0;
left: 50px;
/* solves problem 1 */
float: left;
/* solves problem 2 */
transform: rotate(-90deg) translatex(-$section-sticky-header-height);
height: $section-sticky-header-height;
}
Codepen: https://codepen.io/anon/pen/arybWZ
Edit:
The problem is that I cannot determine the exact width of the sticky header because the h1 text is variable (the client will insert that text via a CMS). Is there a way to handle this? If possible without Javascript
Got it. You can try this instead, if the height is variable:
<h1 class="h1 mb-0 section__title">
<div class="rotation-outer">
<div class="rotation-inner">
<div class="rotation">
STICKY
</div>
</div>
</div>
</h1>
.section__title {
border: 1px solid; // for demo purpose
position: sticky;
top: 0;
float: left;
.rotation-outer {
display: table;
position: relative;
left: 50px;
.rotation-inner {
padding: 50% 0;
height: 0;
.rotation {
transform-origin: 0 0;
transform: rotate(-90deg) translate(-100%);
margin-top: -50%;
white-space: nowrap;
}
}
}
}
See in action: https://codepen.io/anon/pen/BedREm
There's a very good explanation here for how this works: Rotated elements in CSS that affect their parent's height correctly
Edit 2:
At that link I also discovered the writing-mode: vertical-rl; property (in this answer stackoverflow.com/a/50406895/1252920). Do you think could be a better solution? I applied it in this Codepen: codepen.io/anon/pen/JqyJWK?editors=1100 What do you think?
Yes, another sweet alternative, you can use. :)
Here I changed/optimized it a little bit: https://codepen.io/anon/pen/qGXPPe?editors=1100
However, please note that vertical-lr or vertical-rl is not widely supported. Apparently only on desktop version of Chrome/Firefox/Opera. See here.
So, it's up to you, which one to use. Personally, I wouldn't use writing-mode due to lack of browser support.
Seems to me that your Codepen does not have that padding you mention, therefore I wonder if you removed the default padding and margin of html and body elements.
html, body {
margin: 0;
padding: 0;
}
Let me know if it works or in which browser the padding you mention appears.
In this CodePen, the <aside> element wraps the <article> element.
But if you apply a width to the <aside> element (i.e. uncomment width: 50px;), the <aside> jumps to a new row, even though there is enough space to sit alongside the <article> element.
Why doesn't the element sit alongside a floated <article> when space is available?
section {
width: 800px;
}
article {
float: left;
width: 500px;
background: #ffffcc;
}
aside {
/* width: 50px; */
background: #ccffcc;
}
<body>
<section>
<article>[[Text]]</article>
<aside>[[Text]]</aside>
</section>
</body>
Making the <article> semitransparent reveals what is actually happening when the width of the <aside> is auto:
section {
width: 800px;
}
article {
float: left;
width: 500px;
background: #ffffcc;
opacity: 0.5;
}
aside {
/* width: 50px; */
background: #ccffcc;
}
<body>
<section>
<article>[[Text]]</article>
<aside>[[Text]]</aside>
</section>
</body>
That's right: the <aside> element's box stretches horizontally to fill the <section>, disregarding the floating <article> altogether. It's the text within the <aside> that wraps around the <article>, not the box.
So by giving the <aside> a width that is much less than that of the floating <article>, there is in fact no room for the text to sit next to the <article>! This results in the text moving downward instead, since text will always prefer flowing downward to overflowing horizontally. This actually causes the <aside> element's box to increase in height, which can be seen when, again, you make the <article> semitransparent:
section {
width: 800px;
}
article {
float: left;
width: 500px;
background: #ffffcc;
opacity: 0.5;
}
aside {
width: 50px;
background: #ccffcc;
}
<body>
<section>
<article>[[Text]]</article>
<aside>[[Text]]</aside>
</section>
</body>
So why doesn't the in-flow <aside> box itself become narrower or shift downward in response to the float? That's simply because floating takes an element out of the flow. And that's why the initial layout of the <aside> disregards the <article> altogether.
Why does the text wrap around the float, then? Because the entire point of floats is to have text wrap around a floating object, much like how the point of having text at all is for people to read it.
Everything I've described above is covered in section 9.5 of the spec.
Note that this only applies when the <aside> is an in-flow block box that doesn't establish a block formatting context. If you float the <aside> too, obviously it will sit right next to the <article>, since then you have two floats, and two floats will naturally line up with one another.
And if you apply overflow: hidden, causing the <aside> to establish a block formatting context, then it does sit next to the <article>, even though it's not floating (in fact, this prevents the text from wrapping around the float altogether):
section {
width: 800px;
}
article {
float: left;
width: 500px;
background: #ffffcc;
}
aside {
width: 50px;
background: #ccffcc;
overflow: hidden;
}
<body>
<section>
<article>[[Text]]</article>
<aside>[[Text]]</aside>
</section>
</body>
While floats never intrude into other block formatting contexts by nature, the fact that overflow: hidden causes this is an unintuitive side effect that has a bit of history behind it.
no javascript and no screen width media queries
I am trying to find a css-only way to achieve the situation depicted in below image. I couldn't find a way to create the following:
a line of blocks (inline blocks or floated blocks) with variable width, aligned to the right of the line using float:right or right text align
elements that don't fit on the line, wrap to the next line. All elements after the first line have their own line.
I've been experimenting around with several strategies to no avail, I have a feeling that flexbox might help but I'm not very experienced with flexbox and couldn't find a way to use it.
A few things that I have tried:
try to put the elements' content in a :before pseudo element, using content:attr(data-content). The element itself would have no width. On the next line there would be a left floating element with a width of 99.9% that pushes each element on a next line. The problem with this is that the elements on the first line should maintain their normal width and I didn't find a way to do that. The :first-line pseudo-selector is limited to words on the line and doesn't work for inline containers on the line
Alternative to above method: also add :after pseudo elements which are absolutely positioned and have the same content as the :befores. The :before elements would only show on the first line and don't wrap, the :after elements would form the vertical list on the right. Also with this way I walked into a dead end.
UPDATE:
I made a (less) fiddle that works when the elements' widths are fixed and equal. Unfortunately fixed width, so not yet what I want to achieve. If you want to help me you could perhaps use this as a starting point. I put the content in a :before so perhaps it could overflow the element and somehow fix the element width to auto.
currently CHROME only: http://jsfiddle.net/2px3b63j/7/
html:
<div class="pusher"></div>
<nav>
<a data-title="First" href="#"></a><a data-title="Second" href="#"></a><a data-title="Third" href="#"></a><a data-title="Fourth" href="#"></a><a data-title="Fifth" href="#"></a>
</nav>
less:
#h: 3em;
#w:6em;
* {
margin: 0;
padding: 0;
}
body {
font: 0.9rem sans-serif;
background: #666;
}
.pusher {
float: left;
width: ~"calc(100% - " (#w * 1.01) ~")";
height: #h * 6;
-webkit-shape-outside: polygon(0 #h, 100% #h, 100% 100%, 0 100%);
}
nav {
position: relative;
text-align: right;
background: white;
height: #h;
line-height:0;
a {
position: relative;
text-align:center;
width: #w;
max-width: 100%;
display: inline-block;
background: white;
text-decoration: none;
color: #333;
font-weight: bold;
height: #h;
line-height: #h;
&:before {
content: attr(data-title);
}
}
}
LINK TO ANSWER: https://jsfiddle.net/ky83870x/1/ doesn't work in Internet Explorer but I assume it works in Edge. If anyone can find a way to make it work in IE, I will be very interested to know
One posibility to get your output using flex box.
Make the flexbox so narrow that any child will fit. That forces the children to go one in a row.
Add a pseudo element before the first child to force an extra margin.
Justify the flex as needed
And place the flex to the right, because now everything is to the left.
The elements are color coded to see easily what is happening
.container {
display: flex;
flex-flow: row wrap;
border: solid 1px red;
width: 10px;
left: 500px;
position: absolute;
justify-content: flex-end;
}
.container div {
font-size: 20px;
margin: 5px;
background-color: lightblue;
display: inline-block;
flex-basis: auto;
flex-shrink: 0;
}
.container:before {
content: "";
margin-left: -500px;
flex-basis: 10px;
background-color: yellow;
height: 6px;
}
<div class="container">
<div>Lorem</div>
<div>Ipsum dolor sit amet</div>
<div>Consectetur adipisicing elit</div>
<div>Unde saepe</div>
<div>Placeat neque mollitia</div>
<div>Accusamus fuga</div>
<div>Lorem</div>
<div>Ipsum dolor sit amet</div>
<div>Consectetur adipisicing elit</div>
<div>Unde saepe</div>
<div>Placeat neque mollitia</div>
<div>Accusamus fuga</div>
</div>
I currently have something like the following:
Basically it's just three divs contained in one container_div which has its width and height specified. CSS code for the container and the top div looks like:
.container_div{
width: 800px;
height: 500px;
}
.top_div{
width:100%;
height:100px;
}
What I am now trying to do is come up with CSS code for the center_div and bottom_div elements in a way that:
Bottom div has no overflow
Bottom div can grow/shrink without causing its parent element to change its size ( something like bottom:0 absolute positioning )
Whenever bottom div grows, center div shrinks and vice-versa.
This is what should happen when bottom div grows:
I am looking for a pure CSS solution. Firefox support is enough.
This can be easily achieved by a css table layout. In your case, involving table rows, that will (by default) automatically fill the space of it's display: table container.
In your case, just set:
The top div to be a fixed height
The middle div to be 100% height. This will squize the bottom div to its own content height.
The bottom div to be zero height.
body { margin: 0; }
#container {
display: table;
position: absolute;
height: 100%;
width: 100%;
color: white;
}
#container > div:nth-child(1) {
display: table-row;
height: 50px;
background: red;
}
#container > div:nth-child(2) {
display: table-row;
height: 100%;
background: green;
}
#container > div:nth-child(3) {
display: table-row;
height: 0;
background: blue;
}
<div id="container">
<div>div 1 (fixed 100px)</div>
<div>div 2 (expand to fill remaining space) </div>
<div>
div 3 (fit its own content)
loren ipsum dolor sit amet... loren ipsum dolor sit amet... loren ipsum dolor sit amet... loren ipsum dolor sit amet...
</div>
</div>
I am trying to style a block of text so that it is surrounded by a large curly brace on each side (so that each brace takes up the whole height of each side of the element). Here is the HTML:
<blockquote>
<span class="braceleft">{</span>
<p class="quotation">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus Pellentesque at neque lorem, vitae aliquet risus.</p>
<span class="braceright">}</span></blockquote>
I should also mention that I am trying to do this in WordPress, which I know can add unwanted tags. If I could get the right CSS for plain HTML, I can hopefully figure out how to strip the unwanted tags.
I can easily change the HTML markup if that would make styling easier.
Remove the <span> and <p> tags. Edit the opening <blockquote> tag to
<blockquote class="addCurlys">. Use this CSS (play with the font-size for the :before and :after pseudoelements):
blockquote {
font-size:1em;
}
blockquote.addCurlys:before {
content: "{";
font-size:10em;
}
blockquote.addCurlys:after {
content: "}";
font-size:10em;
}
Because em is the unit of measurement for the :before and :after pseudoelements, they're linked to the font-size of their parent - the blockquote itself.
I think most browsers now support :: for pseudoelements - I still tend to only use one
Keep in mind that you should restrict content to make it fit inside curly brackets.
You can probably do something like
<blockquote class="clearfix">
<div class="curly-left float-left">
<div class="float-left"> Content here </div>
<div class="curly-right float-left">
</blockquote>
Then in the CSS you set the hight / width and background image for curly left and right.
Float the divs and use clearfix on the blockquote.
I think that should do it.
Here's the code I use for clearfix
/* Clearfix */
.clearfix:before, .clearfix:after { content: "\0020"; display: block; height: 0; overflow: hidden; }
.clearfix:after { clear: both; }
.clearfix { zoom: 1; }
<span class="braceleft" style="float:left; padding: 0 10px">{</span>
<p class="quotation" style="float:left; padding: 0; margin: 0">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus Pellentesque at neque lorem, vitae aliquet risus.</p>
<span class="braceright" style="float:left; padding: 0 10px">}</span>
The way to do it without additional tags would be to use CSS's :before and :after to create the 2 braces and then style them accordingly.
Consider this code (or test the fiddle):
HTML:
<blockquote class="addCurlys">I like curly <br> curls <br/><br/> I really do<br/><br/>I really really do</blockquote>
CSS:
BLOCKQUOTE.addCurlys {background: yellow; position: relative; padding: 0.5ex; 1em}
BLOCKQUOTE.addCurlys:before {
content: ''; border: 1px dotted pink;
position: absolute; right: 100%; top: 0; bottom: 0; width: 30px;
background-image: url('http://placekitten.com/g/30/60'); background-size: 100% 100%
}
BLOCKQUOTE.addCurlys:after {
content: ''; border: 1px dotted pink;
position: absolute; left: 100%; top: 0; bottom: 0; width: 30px;
background-image: url('http://placekitten.com/g/30/60'); background-size: 100% 100%
}
Here's how it works (for the opening brace): :before creates a pseudo-element. We need to add the content attribute otherwise it won't be rendered 'properly'. The pink border is only there so you can see where it is.
The BLOCKQUOTE is given a position: relative attribute so that the before and after blocks can be positioned relative to it. We give :before a position: absolute and give it a top and bottom value of 0 so that it gets aligned with the blockquote's top and bottom edges. Then we give it a right: 100% so that it gets pushed all the way to the left of the edge (could use left:0 if you want it inside the blockquote, adjust for your tastes). And a width to our liking.
Finally we add a background (since you wanted the curl to stretch vertically) image and specify that we want it to be sized 100% by 100% of the container (:before, i.e. the opening brace). Feel free to change the kitten images to curly braces, I prefer kittens.
Adjust for your needs.