Defining Flex 4 Skins with CSS - apache-flex

I am trying to define my Flex 4 Skins via CSS but I my custom skin will not display. Here is what I am doing:
In my application I import my css and define the styleName in my button:
<fx:Style source="styles.css"/>
<s:Button label="Button" styleName="circle"/>
Here is my CSS:
#namespace s "library://ns.adobe.com/flex/spark";
#namespace mx "library://ns.adobe.com/flex/mx";
s|Button.circle
{
skinClass: ClassReference("skins.buttons.CircleButton");
}
My understanding is that my button should be supplied it's skinClass via the CSS but it fails to work. If I define the skinClass directly like below it works fine:
<s:Button label="Button" skinClass="skins.buttons.CircleButton"/>
Any help would be appreciated.

Make sure you have your CSS file under the root Application file first. Second, I would try to do the css without the type selector, so instead of s|Button.circle, just do .circle.
EDIT
You can also try putting the style in a Style tag within the same container as your button to see if that works. Are you sure your application can find your style.css? Showing more code might help the situation.

Per the official Flex CSS documentation:
Class Selector: A CSS class selector
matches components that meet a class
condition. The CSS syntax to declare a
class selector is to prefix the
condition with a dot. You can either
declare a class selector as a
condition of a type selector, or
universally to any type that meets the
class condition.
.header { background-color: #CCCCCC; }
HBox.footer { background-color: #999999; }
Note: In Flex a class condition is met
using the styleName attribute on a
component. For example, you may have
two classes of HBox: "header" and
"footer". Above, the first selector
applies to any component with
styleName="header"; the second
selector should only apply to HBox
components with styleName="footer"
(something that actually needs to be
fixed and enforced in Gumbo, as
to-date class selectors have only been
universal and any type in the selector
is ignored).
It looks like selectors may not be working in Gumbo...

Related

Using Angular component name in Less stylesheet don't match generated DOM

I'm leaning Angular by following Udemy course and I have this style:
server dl {
display: flex;
}
and server component and it don't work. The style is not applied to html. Because generated style look like this:
server[_ngcontent-c1] dl[_ngcontent-c1] {
display: flex;
}
and DOM look like this:
<server _ngcontent-c0="" _nghost-c1="">
<dl _ngcontent-c1="">
<dt _ngcontent-c1="">Plantform</dt>
<dd _ngcontent-c1="">Linux x86_64</dd>
</dl>
</server>
_ngcontent-c0 instead of _ngcontent-c1, why this is happening? Why the style don't match the DOM?
I'm using Angular app using generated by CLI with Less (but I've created component by hand using server as selector, the same happen if name is app-server).
Why this attribute selectors are added? What about if I use this component in different place? I want to match all elements inside component that's why I've added server as selector to always match all inside this component.
How can I use component name that is added to html as root for my whole style? Or is this not good practice in Angular and this is handled other way, if so can someone explain?
Every element of a component is scoped-automagically / polyfilled by angular (in accordance with css spec for scoping) using those attributes you noticed. So basically, you don't have to write component-name element when you write css for that component but you can just write:
dl {
display: flex
}
Angular will make sure that this style is only applied to dl inside server by using the generated attributes, it is essentially a polyfill for css scoping. If all your targeted browsers support css scoping natively, you can even set ViewEnacpsulation.Native
In some cases where you decide to style the root element, you have to use the special selector :host
The :host selector is the only way to target the host element. You
can't reach the host element from inside the component with other
selectors because it's not part of the component's own template. The
host element is in a parent component's template.
So instead of writing server {background: red} you will write :host {background: red}
This is also inline with css spec for scoping.
Read more about CSS coping and component based CSS to know more about this strategy.
As a primer read the base documentation in Angular
Also, note that you can add your css to any global stylesheet like the way you did:
server dl {
display: flex
}
Which way to go largely depends on how you plan to manage and scale css.
You can use at .TS file below the class.
This is delete all this _ngcontent
#Component
selector,
template,
styles,
This code encapsulation: ViewEncapsulation.None

Overriding the encapsulated CSS of external component

I was wondering how to override the encapsulated CSS of an external component.
So I am using material2 in my project and the tabs component has a the attribute overflow set on tab-body. Is it possible to override the overflow value?
You can use the special css /deep/ instruction. See the documentation
So, if you have
app
sub-component
target-component
<div class="target-class">...</div>
You can put in your apps css (or less):
/deep/ .target-class {
width: 20px;
background: #ff0000;
}
Obviously, you can put this css fragment in sub-component as well.
From this article
Although the style of a component is well isolated, it can still be easily overridden if necessary. For that, we just need to add an attribute to the body of the page:
<body override>
<app></app>
</body>
The name of the attribute can be anything. No value is needed and the name override makes it apparent what its being used for. To override component styles, we can then do the following:
[override] hello-world h1 {
color:red;
}
Where override is the attribute, hello-world is the target component, and h1 is whatever you are trying to restyle. (get this right or it wont work).
Your component hello-world would be
selector: 'hello-world',
styles: [`
h1 {
color: blue;
}
`],
template: ` <h1>Hello world</h1> `
I think this is the most elegant way.
Alternatively if you are building a library of some sort, you can reset the styling altogether by doing something fancy in your css like:
:host-context(.custom-styles) {
//.. css here will only apply when there is a css class custom-styles in any parent elem
}
So then to use your component you'd use
<hello-world class="custom-styles">
But this is way less convenient than the first option.
::ng-deep .tag-or-css-class-you-want-to-override {
/* Add your custom css property value. */
}
The syntax ::ng-deep is used to override outside css class or tags without using ViewEncapsulation.None.
I see variations of this question a lot and since this is the top question on the subject I want to give the simplest answer. ng-deep and similar functionality is deprecated, so it's best to just rely on vanilla CSS.
Simply create a CSS selector with a higher specificity.
Most people (including myself) get hung up trying to do that because they don't understand two things:
Angular View Encapsulation
CSS Specificity
Angular View Encapsulation
View Encapsulation ensures CSS within a component only affects that component. To affect other components, you need some global CSS. You can do this by using a global style file like styles.css or by disabling View Encapsulation on a component.
#Component({
...
encapsulation: ViewEncapsulation.None
})
CSS Specificity
When two selectors select the same element, the CSS that actually gets applied is based on specificity: https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity
You can increase specificity by simply adding more elements to your CSS selector. For example p.className is more specific than just .className. If you're lazy, you can just repeat a class name to increase specificity. .className.className is more specific than .className.
So to override any CSS in an Angular project, go into styles.css and repeat the class selector until your CSS has a higher specificity than the original.
.className.className.className {
color: red;
}
Didn't work? Add another .className.
Just check the class that is being applied to the tabs by the external component (use Inspector or any other tool). In your style css file, add the same name of the class for the tabs and set the overflow property along with adding !important to it to make sure it overwrites the previous one. Also make sure your css link to the page is added after the external component css link if any.
Hope this helps.
::ng-deep .css-class-you-want-to-override{
/*your custom css property value. like below */
background: white !important;
}

Selector for a custom class

Let's say I have a class called TextEditor which extends TextArea, so what's the right selector for this? Selector like .text-editor didn't help.
Well, actually .text-area works fine, but that's no the solution.
CSS isn't aware of the Java classes that you have created. Manually add a CSS class and use that to style it. E.g. class="TextEditor" then style it with .TextEditor
You may define your own selector that customizes the default .text-area selector. And set the id of your custom class with this selector. See the "Changing the table column header style : Customzing" section of this answer.

garbled css name when styling within UiBinder

For my GWT application, I want to show the selected row in a FlexTable, and for that purpose I add a style to the specific row:
#UiField FlexTable productTable;
int row;
[...]
/* select row */
productTable.getRowFormatter().addStyleName(row, "row-selected");
In the corresponding ui.xml file, I have the style added as follows:
ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
xmlns:g="urn:import:com.google.gwt.user.client.ui"
xmlns:u="urn:import:myapplication.client.ui">
<ui:style>
tr.row-selected {
background: #92C1F0;
}
</ui:style>
<g:VerticalPanel>
<g:ScrollPanel>
<g:FlexTable ui:field="productTable" width="100%" height="100%">
</g:FlexTable>
</g:ScrollPanel>
</g:VerticalPanel>
</ui:UiBinder>
This does not work, while adding the style in my global .css file does. In FireBug I see that the name tr.row-selected is garbled into something like: tr.GB1HWLGEI
Why does this not work and how should it work instead?
UiBinder uses ClientBundle for ui:style, so the rules and syntax/features of CssResource apply.
This means that your CSS class names will be obfuscated (so that they're unique and won't conflict with a same-named CSS class from another CssResource or external stylesheet).
In your case, you can either define a CssResource interface and declare the ui:style to extend that interface and inject the instance into a #UiField; so you can use the obfuscated style into your addStyleName; as in http://code.google.com/webtoolkit/doc/latest/DevGuideUiBinder.html#Programmatic_access
Or you can use #external in your ui:style to disable obfuscation for the CSS class; see http://code.google.com/webtoolkit/doc/latest/DevGuideClientBundle.html#External_and_legacy_scopes.
Garbled is really obfuscated which will be faster in the browser and harder for someone to reverse engineer. It also means you don't need to worry about css namespace conflicts.
So, just use the following line in your ModuleName.gwt.xml file during development to disable obfuscation.
<set-configuration-property name="CssResource.style" value="pretty" />

skinClass working in mxml, but not in external css

I have a simple button in a mxml file, if I set the skinClass property in the tag itself it works, however, if I set the skinClass property in an external css file, it doesn't apply to the button.
Works:
view.mxml
<s:Button id="btnRefresh" skinClass="skins.RefreshButtonSkin"/>
Doesn't work:
view.mxml
<s:Button id="btnRefresh"/>
style.css
#btnRefresh
{
skinClass: ClassReference("skins.RefreshButtonSkin");
fontSize: 12px;
}
Someone knows how I can get this css working?
Note: I can apply other styles to the button using the css, eg fontSize works
Edit: Additional info
The button is nested in the actionContent part of my view
view.mxml
<s:actionContent>
<s:Button id="btnRefresh"/>
</s:actionContent>
The css file is declared in my main mxml file
main.mxml
<fx:Style source="style.css"/>
I'm compiling for flex 4.5.1, it's a mobile application
It would seem that this is a bug in the ActionBar component. I've tried id selector (#btnRefresh), class selector (.btnRefreshStyle), component selector (s|Button) and #Thembie's suggestion.
I've tried using skinClass and skin-class.
None of these work when the button resides in the actionContent property of the View component. But it all works fine when you move the button to the View component.
So I'm afraid you're stuck with hard-coding that skinclass. You might consider filing a bug report.
s|Button#btnRefresh
{
skinClass: ClassReference("skins.RefreshButtonSkin");
}
defaults.css in the mobile theme has style rules for ActionBar with a higher CSS "specificity" level than the ID selector you're using.
Short answer: Use #actionGroup #btnRefresh as your selector.
Long answer: ActionBar has the following selectors for rules to support the "defaultButtonAppearance" style in the mobile theme:
ActionBar Group#navigationGroup Button
ActionBar Group#actionGroup Button
ActionBar.beveled Group#navigationGroup Button
ActionBar.beveled Group#actionGroup Button
These are in place to make it easy to swap out the flat-look buttons with the iOS-styled "beveled" buttons.
Jason was right, the default.css in mobile theme override your s|Button#btnRefresh style.
In order for your skin to work, just make your style stronger like:
s|ActionBar s|Group#navigationGroup s|Button#btnRefresh{...}

Resources