0

I'm trying to style placeholders for input fields (for different browsers) in Sass 3.3.1, and want to change the opacity when the field is focused. I'm having a hard time combining the pseudo-class and pseudo-elements with the ampersand. The following gives a compilation error:

::-webkit-input-placeholder,
:-moz-placeholder,
::-moz-placeholder,
:-ms-input-placeholder{

    ... some default styling

    :focus#{&}{
        opacity: 0;
    }
}

Can this be done?

Edit

This is the output I am looking for:

::-webkit-input-placeholder {
    opacity: 1;
}
:-moz-placeholder{
    opacity: 1;
}
::-moz-placeholder{
    opacity: 1;
}
:-ms-input-placeholder{
    opacity: 1;
}
:focus::-webkit-input-placeholder {
    opacity: 0;
}
:focus:-moz-placeholder{
    opacity: 0;
}
:focus::-moz-placeholder{
    opacity: 0;
}
:focus:-ms-input-placeholder{
    opacity: 0;
} 
Willem Van Bockstal
  • 2,233
  • 1
  • 17
  • 24
  • possible duplicate of [Sass .scss: Nesting and multiple classes?](http://stackoverflow.com/questions/11084757/sass-scss-nesting-and-multiple-classes) – cimmanon Oct 29 '14 at 16:58
  • Also note, this selector won't work: http://stackoverflow.com/questions/16982449/why-isnt-it-possible-to-combine-vendor-specific-pseudo-elements-classes-into-on – cimmanon Oct 29 '14 at 17:00
  • @cimmanon Thanks for the help, I didn't know about the second link. But I am stil looking for an easy way to generate the :focus-rules for each vendor. – Willem Van Bockstal Oct 29 '14 at 17:29
  • There's nothing special about `:focus`, it is the same as any other selector as far as Sass is concerned. Your answer is in the 1st link. Also related: http://stackoverflow.com/questions/17181849/placeholder-mixin-scss-css – cimmanon Oct 29 '14 at 17:41
  • I don't see how the first link will lead me to something that outputs `:focus::-webkit-input-placeholder`. I cannot use `:focus&` since there must be a white space before &. Your last link seems more what I'm looking for. Thanks again for the help. – Willem Van Bockstal Oct 29 '14 at 18:04

3 Answers3

3
// Cross-browsers opacity: @include opacity(0.5);
@mixin opacity($opacity) {
    opacity: $opacity;
    $opacity-ie: $opacity * 100;
    filter: alpha(opacity=$opacity-ie); //IE8
}

// Transitions for all: @include transition($transition);
$transition: all .3s ease;
@mixin transition($value) {
    -webkit-transition: $value;
    -moz-transition: $value;
    -ms-transition: $value;
    -o-transition: $value;
    transition: $value;
}

// Input placeholder animation: @include placeholder { color: #000 }
@mixin placeholder {
    &::-webkit-input-placeholder {
        @content;
    }
    &:-moz-placeholder {
        @content;
    }
    &::-moz-placeholder {
        @content;
    }
    &:-ms-input-placeholder {
        @content;
    }
}

// How to use:
input {
    text-overflow: ellipsis;
    color: mediumseagreen;
    @include placeholder {
        color: cornflowerblue;
        transition: $transition;
        @include opacity(1);
    }
    &:focus {
        @include placeholder {
            @include opacity(0);
            transition: $transition;
        }
    }
}
0

This is going to be the other way around, actually:

element:focus{
    &::-webkit-input-placeholder,
    &:-moz-placeholder,
    &::-moz-placeholder,
    &:-ms-input-placeholder{
        opacity: 0;
    }
}

Edit

I seem to have a problem combining them in my testing, but the following should work:

::-webkit-input-placeholder{
   color: red;
   &:focus{
        color: blue;
   }
}

On thing to note, though, is that this only works if they are separated out. You cannot combine multiple pseudo-selectors to one definition (like ::-webkit-input-placeholder, :-moz-input-placeholder{ /* this does not work in my testing */ }).

Update 2

Heres a quick SASS function I mocked up that will simplify the process:

@mixin input-placeholder($all:default){
    @if $all == default {
        $all : ("::-webkit-input-placeholder", ":-moz-placeholder","::-moz-placeholder",":-ms-input-placeholder");
    }
    @each $placeholder in $all {
        #{unquote($placeholder)}{
            @content;
        }
    }
}

You can use it by doing the following:

@include input-placeholder{
    color: red;
    &:focus {
       color: blue;
    }
}

This means you only have to write your code once. It will output all of them on individual lines and apply the same rules to them.

somethinghere
  • 16,311
  • 2
  • 28
  • 42
  • I also have some default placeholder styling when fields are not focused. Can the 2 be combined? Sorry if I was unclear, I updated the original question. – Willem Van Bockstal Oct 29 '14 at 16:51
  • @WillemVanBockstal I have amended by answer and you can sort-of do it but it isn't very fun. You need to keep every pseudo-class separate, otherwise Safari (in my case) just does;t apply them. – somethinghere Oct 29 '14 at 17:03
  • @WillemVanBocstal I have tested my SASS function above and it outputs code that works in safari 8m in my testing, and should work on all other browsers as well. – somethinghere Oct 29 '14 at 17:16
  • I think that in your first edit the order still is wrong, since I need to compile to :focus::-webkit-input-placeholder in this specific order. But thanks, you are right in Update 2, I need to separate each pseudo-class, so I'm gonna try the function! – Willem Van Bockstal Oct 29 '14 at 17:23
  • @WillemVanBockstal The order of elements does not matter in this case, since the only requirement is that both are actually true. So if its focused and selected, then make the color blue, otherwise make the color red. You don't actually need to supply the pseudo-element any element to apply to, so the second one works and outputs code that does what you want it to do as far as I can see :) – somethinghere Oct 29 '14 at 17:26
  • Strange, in my testing in Safari 8 the order does matter: http://jsfiddle.net/willemvb/4mpL9oqv/ What am I missing? – Willem Van Bockstal Oct 29 '14 at 17:42
  • This is very weird.. I'm now testing at home and indeed, this does not work in that order. I'll have a think about this... – somethinghere Oct 29 '14 at 18:40
0

Solution from SASS Compass:

// Style the html5 input placeholder in browsers that support it.
//
// The styles for the input placeholder are passed as mixin content
// and the selector comes from the mixin's context.
//
// For example:
//
//     #{elements-of-type(text-input)} {
//       @include input-placeholder {
//         color: #bfbfbf;
//         font-style: italic;
//       }
//     }
//
// if you want to apply the placeholder styles to all elements supporting
// the `input-placeholder` pseudo class (beware of performance impacts):
//
//     * {
//       @include input-placeholder {
//         color: #bfbfbf;
//         font-style: italic;
//       }
//     }
@mixin input-placeholder {
  @include with-each-prefix(css-placeholder, $input-placeholder-support-threshold) {
    @if $current-prefix == -webkit {
      &::-webkit-input-placeholder { @content; }
    }
    @elseif $current-prefix == -moz {
      // for Firefox 19 and below
      @if support-legacy-browser("firefox", "4", "19", $threshold: $input-placeholder-support-threshold) {
        &:-moz-placeholder { @content; }
      }
      // for Firefox 20 and above
      &::-moz-placeholder { @content; }
    }
    @elseif $current-prefix == -ms {
      &:-ms-input-placeholder { @content; }
    }
  }
  // This is not standardized yet so no official selector is generated.
}
Jazi
  • 6,569
  • 13
  • 60
  • 92