Ionic-framework: ion-button ignores --background variables if a color is set

Created on 30 Jan 2019  路  7Comments  路  Source: ionic-team/ionic-framework

Bug Report

Ionic version:

[x] 4.0.0

Current behavior:
In a corporate theme I'm required to add a gradient to all buttons. The gradient is derived from the color property that is set to a component.

In the betas and as far as I know also in the RCs of Ionic I could override the background like this:

ion-button[class*="ion-color-primary"]:not(.button-outline):not(.button-clear) {
  --background: linear-gradient(
    to bottom,
    #000 0%,
    #fff 100%
  );
}

Unfortunately this approach has now also stopped working.
It would be great if I could just do something like this:

ion-button {
   &.ion-color-primary {
      --background: #somecolor
   }
}

Expected behavior:
I think the --background property should always be respected, regardless of the button type.
Currently it seems like the --background variable is only used for some of the button types. For solid color buttons the background is just set without using the variable: https://github.com/ionic-team/ionic/blob/74ce34fa68b926777a4166c5eb815866433ae91e/core/src/components/button/button.scss#L86

I think it should rather be

background: var(--background, current-color(base));

Steps to reproduce:
Try to override the background variable for a button like this:

<ion-button color="primary">test</ion-button>

Related code:

Ionic info:

Ionic:

   ionic (Ionic CLI)          : 4.1.1 (/usr/local/lib/node_modules/ionic)
   Ionic Framework            : @ionic/angular 4.0.0
   @angular-devkit/core       : 7.2.3
   @angular-devkit/schematics : 7.2.3
   @angular/cli               : 7.1.4
   @ionic/ng-toolkit          : not installed
   @ionic/schematics-angular  : not installed

System:

   NodeJS : v11.8.0 (/usr/local/Cellar/node/11.8.0/bin/node)
   npm    : 6.5.0
   OS     : macOS
triage

Most helpful comment

The problem is that the Ionic color CSS variables are used for so many different CSS properties that it wouldn't work to add a gradient through the base CSS variable that the colors use, thus making it hard to pass a gradient background using our color property. For example, our checkbox uses the base of the color (--ion-color-base defined for each color here: https://github.com/ionic-team/ionic/blob/master/core/src/css/core.scss#L36-L56) for a border and background color.

We added the color property so users can quickly theme some component colors with a single property, without having to dive into the CSS of it all. While I understand your use case, it is complex and not what color was intended for. We decided that the most common use case: styling all of the buttons with a quick background change, should be the default. Developers should be able to change the background/color of buttons by adding CSS, or quickly add color to use the colors we provide.

Using my 1st example above would allow you to still use the Ionic colors with the gradients, without having to hardcode the value of the Ionic colors.

Now developers will need to think about which color/gradient classes to add.

I think I would be able to help more if I could see how people are using this application. It sounds like you are creating a single app that can have the colors changed based on the company?

If you really wanted to, you could override the CSS variables that the color uses, but this is not part of the public API, it is how Ionic sets the colors internally:

ion-button.ion-color-primary {
  --ion-color-base: linear-gradient(
    to bottom,
    var(--ion-color-primary) 0%,
    var(--ion-color-primary-contrast) 100%
  ) !important;
}

https://codepen.io/brandyscarney/pen/daNPox?editors=1100

All 7 comments

Thanks for the issue. This is by design and was decided in the early betas (see #14853). The color property will always take precedence over the individual CSS properties. This is because you could do the following:

ion-button {
  --background: red;
}

and while you'd want all buttons to be background red, you wouldn't want a button that has <ion-button color="primary"> to have a red background. The thinking is that if you don't want to use the background that comes with the color property, you shouldn't add the property at all, and you should use your own CSS or add a new color instead.

It's hard for me to know what exactly you're trying to accomplish without pictures, but below are two ways you can achieve the background color based on our Ionic colors.

You should have the Ionic colors defined in your project for use. If you're using Angular it would be here: https://github.com/ionic-team/ionic-conference-app/blob/master/src/theme/variables.scss

Add a New Color

Codepen: https://codepen.io/brandyscarney/pen/wNobdY

Here is the CSS from the Codepen:

.ion-color-primary-gradient {
  --ion-color-base: linear-gradient(
      to bottom,
      var(--ion-color-primary) 0%,
      var(--ion-color-primary-contrast) 100%
    );
  --ion-color-base-rgb: 56, 128, 255;
  --ion-color-contrast: #ffffff;
  --ion-color-contrast-rgb: 255, 255, 255;
  --ion-color-shade: #3171e0;
  --ion-color-tint: #4c8dff;
}

screen shot 2019-01-30 at 3 12 44 pm

Define Color Classes

Codepen: https://codepen.io/brandyscarney/pen/OdbKyR?editors=1100

This is easier to do with Sass loops, but if you're just using CSS it would be like the following:

<ion-button class="my-primary">
  Primary
</ion-button>
.my-primary {
  --background: linear-gradient(
    to bottom,
    var(--ion-color-primary) 0%,
    var(--ion-color-primary-contrast) 100%
  );
}

Thank you for the fast and complete answer!
It would have been really great to continue using our old way of targeting the buttons based on the ion-color class added. This had the big advantage that developers using the theme could just use the default ionic colors and still adhere to the corporate design guides that includes some subtle gradients for some components. Now developers will need to think about which color/gradient classes to add.

I think the custom color approach might still be usable for now, it just feels a bit strange to assign a gradient to a variable that's named color and not background :-)

In your example developers could still have used something like this easily:

ion-button:not(.ion-color) {
   --background: red;
}

The problem is that the Ionic color CSS variables are used for so many different CSS properties that it wouldn't work to add a gradient through the base CSS variable that the colors use, thus making it hard to pass a gradient background using our color property. For example, our checkbox uses the base of the color (--ion-color-base defined for each color here: https://github.com/ionic-team/ionic/blob/master/core/src/css/core.scss#L36-L56) for a border and background color.

We added the color property so users can quickly theme some component colors with a single property, without having to dive into the CSS of it all. While I understand your use case, it is complex and not what color was intended for. We decided that the most common use case: styling all of the buttons with a quick background change, should be the default. Developers should be able to change the background/color of buttons by adding CSS, or quickly add color to use the colors we provide.

Using my 1st example above would allow you to still use the Ionic colors with the gradients, without having to hardcode the value of the Ionic colors.

Now developers will need to think about which color/gradient classes to add.

I think I would be able to help more if I could see how people are using this application. It sounds like you are creating a single app that can have the colors changed based on the company?

If you really wanted to, you could override the CSS variables that the color uses, but this is not part of the public API, it is how Ionic sets the colors internally:

ion-button.ion-color-primary {
  --ion-color-base: linear-gradient(
    to bottom,
    var(--ion-color-primary) 0%,
    var(--ion-color-primary-contrast) 100%
  ) !important;
}

https://codepen.io/brandyscarney/pen/daNPox?editors=1100

thank you so much.
I was really sure I tried that approach already but probably I forgot to add the !important. This will work perfectly for us, and I won't blame you in case that private api breaks at some point... that's something for future me to worry about :-)

Basically we are creating a theme in a big company, that theme will be used by many developers in different corporate apps and in teams around the world. However we want to stay as close to the ionic standards as possible (e.g the default color names) but still have some special things like the gradients .

Awesome! I'm glad that works for you. That makes sense. If I'm understanding correctly then it's mostly to be able to follow along with the Ionic documentation but still get the small UI changes that you'd like. So it's somewhat of an application shell that will apply throughout the company?

I think that will be the best for right now since it is such a specific use case, but if anything happens in the future to where you can no longer accomplish this easily, please ping me. 馃檪

Exactly :-) That's my main goal, developers should just be able to use the Ionic docs. This approach has been working great for us since Ionic 1.

They still need to load the theme and our custom component package, but apart from that they can just use whatever code snippet they find in the community / docs and still have the basic corporate design.

Thanks for the issue! This issue is being locked to prevent comments that are not relevant to the original issue. If this is still an issue with the latest version of Ionic, please create a new issue and ensure the template is fully filled out.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

SebastianGiro picture SebastianGiro  路  3Comments

brandyscarney picture brandyscarney  路  3Comments

Macstyg picture Macstyg  路  3Comments

BilelKrichen picture BilelKrichen  路  3Comments

manucorporat picture manucorporat  路  3Comments