27

I am trying to hide the following element in an automatically generated HTML document:

  <p id="sitspagedesc" class="sitspagedesc">

    </p>

In some pages, the <p> tag will contain an inner value but in others it can contain only spaces as shown in the example. I need to find a way of hiding this so that it is hidden using CSS only, as changing the HTML is not an option.

I have tried to hide it using

.sitspagedesc:empty
{
display:none;
}

but this does not work, presumably on the account of the spaces the element contains.

Does anyone have any good ideas?

Thanks :)

Andy
  • 14,427
  • 3
  • 52
  • 76
Andy Kaufman
  • 761
  • 3
  • 9
  • 21
  • 1
    Hate to say it, but is Javascript not an option? – A.M. D. Nov 14 '12 at 14:42
  • 2
    Why do you have an empty `p` in the first place? I would recommend placing some server side logic to not even render this element if you don't want to display it. What you are trying to achieve seems counter intuitive – Curtis Nov 14 '12 at 14:44
  • To clarify... do you have potentially many `

    ` tags with that class? or are you looking to handle this specific element by ID?

    – scunliffe Nov 14 '12 at 14:44
  • No CSS way according to http://stackoverflow.com/questions/1520429/css-3-content-selector – sglessard Nov 14 '12 at 14:48
  • Stupid question of course, but don't empty `

    `s get hidden automatically by the browsers?

    – Mr Lister Nov 14 '12 at 15:40
  • The HTML is being generated by a database where some values in this field may contain spaces due to user error. There are potentially many of these

    tags with this class, but I think javascript is probably the best option.

    – Andy Kaufman Nov 14 '12 at 16:04
  • @MrLister sort of... if the `

    ` tag has a style to say include a default width/height/border etc. that will still show up.

    – scunliffe Nov 14 '12 at 18:34

9 Answers9

14

I don't think you can do it with pure CSS.

However with a little JavaScript you can do it.

var allParas = document.getElementsByTagName('p');
//filter by class name if desired...
for(var i=0;i<allParas.length;i++){
  if(allParas[i].getElementsByTagName('*').length == 0){
    allParas[i].style.display = 'none';
  }
}

If you have access to jQuery it is a little easier to do the filtering with their built in selectors.

$('p.sitspagedesc').each(function(){
  if($(this).children().length == 0){
    $(this).hide();
  }
});
scunliffe
  • 62,582
  • 25
  • 126
  • 161
  • I tried this answer on my WordPress site, and it didn't work. WordPress automatically puts in

    and
    tags (wpautop). My client won't allow me to turn that off, which led me here.

    – David Jul 02 '13 at 02:03
8

If the desire is to mimic the functionality of the :empty selector except that whitespace is ignored, the accepted answer (by scunliffe) doesn't quite work. It only checks for child elements, and this doesn't account for text directly inside the selected element. For instance, <p>Hello World!</p> would be treated as empty because it has no child elements even though it does contain non-whitespace text.

My solution uses the jQuery.trim() function to remove leading and trailing whitespace from the .text() value which contains the combined text contents of the selected element and its descendants. So the selected element is hidden if it contains no non-whitespace text and no child elements. As with the :empty selector, HTML comments are not counted as content since they are not reflected in either the .text() or .children() values.

$('p.sitspagedesc').each(function(){
    if($.trim($(this).text()) == '' && $(this).children().length == 0){
        $(this).hide(); 
    }
});

See the Fiddle at https://jsfiddle.net/TNTitan89/crejkbxq/.

Community
  • 1
  • 1
Garland Pope
  • 3,242
  • 1
  • 25
  • 19
4

The :empty selector is indeed very strict. An element containing a space is not considered empty. So there are two solutions

  1. Modify the output. Trim the values you output or minimize the HTML, so those spaces are removed. Or even better: don't render those elements at all. I think that is the best option, because it both minimizes traffic and gives you a solution that works without Javascript.
  2. Use Javascript to find those elements. I'm not aware of tricks that let you find these elements easily, so you may have to run through all elements, searching for ones you consider empty and add a class to those elements. This may be very slow, especially on low end devices. Also, it will only hide the elements once the script is run, so on page load the element will be visible for a short while until it is hidden. It may be clear that this isn't the ideal solution.

Maybe you can combine both. The :empty selector is a CSS3 selector and is not yet supported by IE8 and before, so a Javascript fallback might be a good idea for those browsers, unless you can fix the server side scripting so that the empty elements are not rendered at all, or are given your special class during rendering, so no Javascript is needed.

GolezTrol
  • 114,394
  • 18
  • 182
  • 210
  • 1
    Looked for a couple hours before I came to this solution. "An element containing a space is not considered empty. So there are two solutions.", saved me! Thanks! – Bryan Saxon Oct 12 '16 at 18:56
4

Answer: Not yet, but it's drafted.

https://drafts.csswg.org/selectors-4/#the-blank-pseudo

...and —at least for Mozilla— there's already a prefixed implementation... :-moz-only-whitespace:

http://jsfiddle.net/peayLrv3/

Frank N
  • 9,625
  • 4
  • 80
  • 110
0

There's no way to detect empty elements in pure CSS (as yet). If Javascript isn't an option, is there anything you can do server-side to manipulate the HTML before it reaches the browser?

A.M. D.
  • 928
  • 6
  • 10
0

Here is my solution which I just implemented for a client using jQuery 1.5.x - you might have to adjust the //skip empty tags but which are valid regular expression string.

$('*:only-child:empty').each(
    function(index) {
        var currentElement = $(this);
        // skip singleton tags
        if(/^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i.test(currentElement.get(0).tagName) == true) {
                return
        }
        // skip empty tags but which are valid
        if(/^(?:textarea)$/i.test(currentElement.get(0).tagName) == true) {
                return
        }
        while (currentElement.parent().children().length == 1) {
            currentElement = currentElement.parent();
        }
        // so 0 or more children for the parent then we hide it
        // we will never have more then 0 children though the :empty takes care of that
        console.log('hidding: ' + currentElement);
        currentElement.hide()
    }
);
Daniel Sokolowski
  • 11,982
  • 4
  • 69
  • 55
0

While not a standard, Firefox has ":-moz-only-whitespace".

Also, for some "future proofing", css-tricks mentions a :blank selector that will be part of the CSS Selectors Level 4 draft. While no current browser supports it, it is a possibility.

Fewfre
  • 1,461
  • 3
  • 19
  • 32
-1

css:

.sitspagedesc:empty
{
display:none;
}

jquery:

$('.sitspagedesc').html(function(){
// empty element
return $.trim($(this).html());
});
-4

You could use:

p.sitspagedesc {
  content: " "; 
  display: none;
}

Unless you randomly have multiple spaces in there...

Tim Lewis
  • 27,813
  • 13
  • 73
  • 102
Thomas
  • 1
  • 1
  • This is totally wrong. [`content`](https://developer.mozilla.org/en-US/docs/Web/CSS/content) will be ignored entirely because it is only a valid property on the `::before` and `::after` and [pseudo-elements](https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-elements). This will simply hide all instances of `.sitspacedesc` including those with content. – Ansel Santosa Jan 23 '15 at 21:47