css or html5 for first and last elements - css

Users can enter descriptions which may include paragraphs or lists. Or they may just enter text without any enclosing <p> or <ul> elements. What I need to do is remove most of the padding and margin above the first element and below the last element so that the user entered content has a nice tight border around it. So I could do one of the following:
Use a css rule I was unaware of to target only the first and last elements
Use css3 or html5 (I assume there's something within these to easily do what I want) and hope everyone upgrades their browsers asap while the older browsers just get a slightly uglier version of the page
Find the first and last elements with Javascript and modify accordingly
Modify the html to add a class like <p class="first">
Ideally the 1st solution exists, does it? I'm ok with the 2nd solution though if not, does it exist? The last 2 I don't care for...
UPDATE: don't care about IE6. But I do need to deal with the situation that if there's just text to begin with, without any <p> or <ul> or other elements, then actually nothing special needs to be done for the top margin/padding.

Use :first-child and :last-child like this. Note that > and :first-child (CSS2) doesn't work in IE6 and below, and :last-child (CSS3) doesn't work in IE8 and below. The only real workaround to both is to use a .first and .last class respectively (you can add them dynamically with JavaScript as Phrogz says).
.description > p, .description > ul {
margin: 1.5em 0;
}
.description > :first-child {
margin-top: 0;
}
.description > :last-child {
margin-bottom: 0;
}
I added the > combinator to prevent elements like strong or li getting selected. What does it mean?

Something like this?
.container * + p, .container * + ul
{
margin: 1em 0 0;
}
.container p, .container ul
{
margin: 0;
}

BoltClock's answer works great in most cases, but IE8 and earlier ignores the :...-child pseudo-selectors.
You can use jQuery to accomplish the same thing, while targetting more browsers.
//On ready...
$(function(){
//Update styles dynamically
$('ul:last').css({'margin-bottom':0,'padding-bottom':0});
$('ul:first').css({'margin-top':0,'padding-top':0});
});

Have you considered wrapping the content in a container with a negative margin? It requires the content to at least be wrapped in a single p element (not hard to test/add melodramatically).
CSS:
.container {border:1px solid black;}
.container .subcontainer {margin:-1em 0;}
.container p {margin:1em 0;}
HTML:
<div class="container"><div class="subcontainer">
<p>My first paragraph.</p>
<p>My second paragraph.</p>
</div></div>

Related

Using :not() selector to style <a> elements not inside <p> elements

I am trying to style any <a> in my website that doesn't appear inside a <p> to look more like a button.
I have been looking at the :not() selector and think this should work to select them:
:not(p) a {}
However doesn't seem to work in the way I expect. I have a codepen here as an example
https://codepen.io/pummra/pen/eYJoNqd
You can address the direct children in the selector using > between the two tags:
:not(p) > a
Otherwise that selector (without the >) would almost always apply, since an a tag inside a p tag is for example also a (not direct) child of the body tag.
Applied to your Codepen example:
a {
color: #00f;
}
:not(p) > a {
background-color: #1779ba;
color: #fefefe;
display: inline-block;
vertical-align: middle;
margin: 0 0 1rem 0;
padding: 0.85em 1em;
}
<div>
<h1>An interesting article</h1>
<p>This is an interesting article about something. There will be a bunch of copy here. Some of it might even have a link in. The links in the copy would look like normal links. The links outside of the paragraph should look like buttons.</p>
Read more about this
</div>

selector in IE7

I'm using css2 to implement some fixes for IE7 on a website.
So I have to put margin-top:30px and margin-bottom:-30px a <h2> title but I dind't find right selector.
<div class="ui-content">
<h2>Text</h2>
<ul class="ui-listview">
List Items
</ul>
</div>
The fact is that Everytime there is a H2 followed by a UL, I must put those two properties, so I wanted to do a selector with h2 and ul, but I don't know wich ones...
Thanks to help me
You can't select h2s followed by uls but you can do it the other way round. E.g.
h2 + ul { /*your css to style the ul*/ }
So you could put fixes/negative margins or whatever on the ul?
This is a only-ie-7 selector:
IE 7 only
*:first-child+html h2 {}
Anyhow, I don't recommend it because almost no one uses this browser anymore, so neither should you program specially for it.
Everytime there is a H2 followed by a UL, I must put those two properties, so I wanted to do a selector with h2 and ul
As stated by #Spudley and #Coop, you can't select an element that is followed by another element (except rare cases with series of li or td or th and :nth-last-child() but it's more of a trick).
The closest thing you can do in pure CSS is testing if h2 is followed by (an)other element(s) or not, i.e. if it's not alone with :only-child pseudo.
From MDN:
The :only-child CSS pseudo-class represents any element which is the only child of its parent. This is the same as :first-child:last-child or :nth-child(1):nth-last-child(1), but with a lower specificity.
Support is IE9+ so if you want to style this element in IE7 and IE8 too (or in the precise case where it's followed by ul but not p or h3...), you'll need JavaScript or to add a class server-side and style this class.
.ui-content > h2:not(:only-child) {
margin-top: 30px;
margin-bottom: -30px;
}
EDIT:
You can also test if H2 is both the :first-child and the second-to-last child of its parent so it'll be styled if it's followed by whatever element but not if this second element has other siblings (third, fourth one, etc)
.ui-content > h2:first-child:nth-last-of-type(2) {
margin-top: 30px;
margin-bottom: -30px;
}
Simplest code would be ;)
<div class="ui-content">
<h2 class="followed-by-list">Text</h2>
<ul class="ui-listview">
List Items
</ul>
</div>
.followed-by-list {
margin-top: 30px;
margin-bottom: -30px;
}
Other trick that'd mean a complete overhaul of your project (say, for next project ;) ): never set a single margin-bottom to content elements (I mean h2, ul, p, etc. It's OK for div and below "blocks") and always set a margin-top to:
an element (general case) ex: p
if needed, an element coming after another like elt1 + p would have a certain margin-top, elt2 + p another one, etc

html <span> tags around tables, lists

I am working on a project where I am sending html to a PDF creator, so I'm not too worried about proper html as long as it shows up correctly on the PDF.
I am currently working on a PDF where about half the page is in a different size font than the other. I was hoping to accomplish this easily by putting tags around the selection. However, there are tables and lists which are not inheriting the css styles.
For example:
CSS:
.fs8
{
font-size:8pt;
}
HTML:
...
<p>Size 10 text here...</p>
<span class='fs8'>
<p>This text is size 8</p>
<table>
<tr>
<td>This text is NOT size 8</td>
</tr>
</table>
<p>Still size 8...</p>
<ul>
<li>NOT size 8!
</ul>
</span>
<p>Size 10 again...</p>
Is there any good way to span across tables and lists, so I don't have to add class tags in hundreds of places?
Not sure if i got what you meant but from what i understand you want to refine your selectors.
Try this:
.fs8 td,
.fs8 li
{
font-size:9pt;
}
This would set font-size to 9pt in any td or li tag inside an element with class fs8.
you should use a div instead of a span because span is by default an inline element, meaning it should not contain block level elements, such as table or ul. Now for the CSS.
.fs8 {
font-size: 8px;
}
.fs8 table,
.fs8 ul {
font-size: 10px; /* not 8px */
}
That should do the trick. You will not need to add classes to any items except the wrapping div, remember it cannot be a span, so replace it with a div for proper behavior.
Using span tags around table elements is simply invalid markup, so all bets are off. Consider using div instead or directly assigning the desired CSS properties to applicable elements.
I know you don't want to do the class tags but you don't have to put it on all of them. you can just put a div around the entire thing, not a span tag those can be overridden by outer settings. I have had that issue before so do something like this:
<div id="my_settings">
<table>.....
</table>
<ul>....
</ul>
</div>
then in your css do this:
#my_settings li, #my_settings li, #my_settings p{
font-siz: ....;
}
I'm not entirely sure if this is what you want but it might be easier than adding a class to all of them.
Since you want a quick and possibly dirty solution, you could use the wildcard selector
.fs8, .fs8 *, .fs8 * *, .fs * * * { font-size:8pt; }
(you need all 3 for tables (span > table > tr > td)
Although, be warned that there might be undesirable side effects!
Also, you should be careful about the tool you use to generate PDF, some generate the file using an old browser rendering engine (hello ie6 rendering). In fact, it's probably why you are having issue, as this example works perfectly on ie8, but not in quirk modes..
I'm not sure about your question, but I will try to anwser:
p { font-size:10px; }
.fs8 p { font-size:8px; }
or
p, td, li { font-size: 10px; }
span.fs8 p { font-size:8px; }

Display first letter only

Lets say this markup:
<div id="socialMedia">
<a class="Twitter">Twitter</a>
</div>
What i want is only to be visible the first letter of the text (in this case, just a T)
(Actually I won't end up using it but I am curious about this; sure can be helpfull later)
So this was my a attempt:
#socialMedia .Twitter{
display:none;
}
#socialMedia .Twitter:first-letter {
display: block !important;
}
I was able to check that it won't achieve it. Question is why? and is there some work-around this?
-EDIT-
We are looking for IE=+7/8 version capable solutions..
Salut
Try something like this:
.Twitter {
font-size: 0;
}
.Twitter:first-letter {
font-size: 12px;
}
<div class="Twitter">Twitter</div>
Maybe this is not the best solution, but it works.
Edit: Disclaimer: this does not work according to comments. Please don't use as-is without checking it fits your needs.
If you check the specification for the :first-letter pseudo-element, you'll notice the following:
The :first-letter pseudo-element must select the first letter of the first line of a block, if it is not preceded by any other content (such as images or inline tables) on its line.
The important word here is "block."
You are trying to use the pseudo-element on an <a/> tag with class of Twitter. By default, anchor tags are inline elements (not block level elements).
For your given markup, one solution to your problem would be to style the anchor this way:
.Twitter {
display:block;
visibility:hidden;
}
.Twitter:first-letter {
visibility:visible;
}​
I'm not sure exactly what you are going for, but that is good enough for experimental purposes. Check out a demo here: http://jsfiddle.net/H7jhF/.
Another way is to use color: transparent
.twitter{
display: block;
color: transparent;
}
.twitter:first-letter{
color: #000;
}
<div id="socialMedia">
<a class="twitter">Twitter</a>
</div>
JSFiddle
However, this won't work for lte IE8.
References:
IE7 IE8 IE9 color:transparent property
color: transparent is not working in Internet Explorer
What you're doing is like hiding a parent element and trying to show one of its children, it won't work because the parent's style overrides it. The parent element also has to be a block level element for it to work. Like a div or p tag, or display: block; on the a tag.
Here's something using color:
HTML
<div id="socialMedia">
<a class="Twitter">Twitter</a>
</div>
CSS
body {
background-color:#FFF;
}
.Twitter{
display: block;
color:#FFF;
}
.Twitter:first-letter {
color:#000;
}
shoot the content off the page and show the letter using dynamic content:
.twitter{
text-indent:-9999px;
display:block;
position:relative;
}
.twitter:before,.twitter::before{
content:"T";
position:absolute;
width:10px;
height:15px;
z-index:100;
text-indent:9999px;
}
at play in this fiddle:
http://jsfiddle.net/jalbertbowdenii/H7jhF/67/
Why not just use JavaScript and split the string into an array and use the first item in the array. Or charAt()
The pure-CSS answers use visibility and color tricks to hide the remaining letters, but they are still present and affecting layout. It could cause layout issues, e.g. if you wish to float the element and put something beside it.
I found a funny way to do this without hidden elements. The trick is to shrink the entire word down to almost nothing and then blow up just the first letter. It's a bit like OP was trying to do, but it works because it's operating on a continuous spectrum rather than display: none which just shuts down anything inside it. (Kind of an analogue > digital situation.)
Demo
HTML:
<div>Ding Dong</div> and other stuff
CSS:
div {
font-size: 0.0000016px;
float: left;
}
div::first-letter {
color: red;
font-size: 10000000em;
}
Result:
Here's what I do:
.Twitter{
display:block;
width:1ch;
overflow:hidden;
white-space: nowrap;
}

Removing top margin from first element using modern CSS

Is it possible with CSS and the latest Chrome or Firefox to automatically remove the top margin from the first <h1> tag, or do I have still have to use jQuery?
You just need h1:first-child { margin-top: 0px; } DEMO
There's no :first-of-page selector so no, you can't use CSS for sure. No way in CSS to extract all h1 from a page whatever their parents and preceding siblings and only take the first one.
You need to know a little bit more about your h1 elements.
Examples:
you can select the first h1 if it's also the (first and or only) child of body > header (or #header in HTML 4.01)
if all h1 are siblings, then h1:first-of-type is the first one for sure
if the first h1 is right after your main nav in a section, then body > nav + section > h1 would select it. Or maybe body > header > nav + section > h1:first-of-type
div#content h1:first-child { margin-top:0; }
AFAIK This won't work in IE6 and may be buggy in IE7.
Pseudo selectors.
h1:first-child {
margin-top: 0;
}
Note that those aren't supported in Failbrowsers (IE 7 and previous), so you may still need a jQuery backup solution.
Add a class to the h1 tag, like:
<h1 class="first">Your text</h1>
Then in the css:
.first
{
margin-top: 0;
}

Resources