Hi - I am trying to update only a few elements using CSS, however as soon as I provide my CSS style, elements for which I did not specify a style also change.
For example in the attached picture (left=document with no cssstyle statement; right=document with cssstyle element as per code):
The following is my sample code:
ods pdf file="c:\temp\cssChecking.pdf" startpage=never
cssstyle="c:\temp\mycssstyle.css";
title "Report Header";
title 'A List';
proc odstext;
list;
item "Item 1" ;
item "Item 2" ;
item "Item 3" ;
end;
end;
run;
title 'A Plot - no colour';
proc sgplot data=sashelp.cars;
histogram weight;
xaxis grid display=(noline) label='Weight';
yaxis grid display=(noline);
run;
ods exclude all;
proc report data=sashelp.cars out=temp;
column origin msrp pctMsrp invoice pctInvoice;
define origin / 'Origin' group;
define msrp / 'MSRP' analysis sum format=comma13.;
define pctMsrp / '%MSRP' computed format=percent8.2;
define invoice / 'Invoice' analysis sum format=comma13.;
define pctInvoice / '%Invoice' computed format=percent8.2;
compute before;
totMSRP = msrp.sum;
totInvoice = invoice.sum;
endcomp;
compute pctMsrp;
pctMsrp = msrp.sum / totMSRP;
endcomp;
compute pctInvoice;
pctInvoice = invoice.sum / totInvoice;
endcomp;
run;
ods exclude none;
proc transpose data=temp(where=(_break_ is null)) out=temp;
by origin;
var pctMsrp pctInvoice;
run;
proc sgplot data= temp ( rename=(col1=value _label_=measure));
vbar origin/ response=value group=measure groupdisplay=cluster;
format value percent6.0;
label measure='Measure' value = 'Value';
run;
proc datasets nolist;
delete temp;
run;
ods pdf close;
And here is the code from the css file:
@import 'C:\temp\normal.css'; .body, .systemtitle, .header .roweader, .data { font-family: arial, sans-serif; } .systemtitle { color: blue; } .listitem, .listitem li::marker { list-style-type: circle; } .graph { border: none; } .graphcharts { border: none; }
What is the best way for updating the style of only a few elements using a .css file?
All help will be much appreciated.
Thanks,
Marie
Hi:
Just a comment. I'm not sure I would ever use Arial with ODS PDF. As this paper explains http://support.sas.com/resources/papers/proceedings10/035-2010.pdf -- Albany AMT is the "Arial" lookalike. In the early days of ODS (back in V8), when you used "plain" Arial with ODS PDF, behind the scenes, it got Helvetica substituted for it in order to be rendered by Adobe.
I am not sure your @import inside the CSS file is going to work the way you want. And I am pretty sure that if you tried parent= in PROC TEMPLATE, it would not work either But if you have already made a copy of normal.css, then this should work:
filename ncss 'c:\temp\normal.css';
filename excss 'c:\temp\extra.css';
proc template;
define style mycss_style;
import ncss; /* import normal.css first */
import excss; /* then import extra css */
end;
run;
** change order of import;
proc template;
define style mycss_diff;
import excss;
import ncss;
end;
run;
When inheritance is resolved in the 2 CSS files, the CSS file listed last should override the CSS file listed first. For example, if you have .Header color: red in the extra.css file but it is not red in the normal.css file, then the color listed last for .Header should be the one that "wins".
For more information, I recommend this paper https://support.sas.com/resources/papers/proceedings13/365-2013.pdf . And for more in-depth help, I recommend working with Tech Support because I do not know whether all of the CSS techniquest used in the paper will work with ODS PDF in the same way they work with ODS HTML.
cynthia
Hi Cynthia - Thanks your feedback and references, however, unfortunately your method seems to have the same effect.
I took normal.css from C:\Program Files\SASHome\SASEnterpriseGuide\7.1\Styles. However, it appears that this stylesheet is not used (despite having it listed in Tools > Options > Results > PDF > Style. Because when I specify ncss (without ecss), I get the lines around the text lists and strong borders around the charts etc.
If I change the underlying style to Sapphire (using your method or the original), I no longer have the borders around the text lists, but still have strong gridlines, etc in the charts.
I have tried taking away all borders and gridlines in a copy of normal.css and they still persist in the PDF output. What I need to find is the stylesheet used to generate the PDF option when no style / stylesheet is specified .... or otherwise learn which part in the CSS file I need to change (or what I need to add) to remove the resulting strong chart gridlines, chart borders, etc...
Hi:
So here's what I did. I started with a copy of PEARL.CSS, which is a copy of the PEARL style definition. Then I changed the .systemfooter class selector in the CSS file to be a purple, because I always wanted to be able to see the PEARL was used. So in the PEARL.CSS file, this is all I changed:
.systemfooter
{
background-color: #FFFFFF;
color: purple;
font-family: 'Albany AMT', Albany;
font-size: 11pt;
font-style: normal;
font-weight: bold;
}
(All of PEARL.CSS is too lengthy to post here. The whole file was c:\temp\PEARL.CSS)
Then I made a second CSS file that had some fairly noticeable color and font changes. I used Courier New to be really certain when that CSS file was used:
.body, .systemtitle, .header, .roweader, .data {
font-family: Courier New;
}
.header {
color: red;
}
.systemtitle {
color: green;
}
.listitem, .listitem li::marker {
list-style-type: square;
color: green;
}
.graph {
border: none;
}
.graphcharts {
border: none;
}
and that file was stored in: c:\temp\extrastyle.css
Then I had 2 FILENAME statements and made 2 different templates, just switching the order of the 2 CSS files:
filename pcss 'c:\temp\pearl.css';
filename css 'c:\temp\extrastyle.css';
proc template;
define style mycss_style;
import pcss; /* import pearl.css first */
import css; /* then import extrastyle.css */
end;
run;
** change order of import;
proc template;
define style mycss_diff;
import css;
import pcss;
end;
run;
ods _all_ close;
ods html file="c:\temp\cssChecking1.html" style=mycss_style;
ods rtf file="c:\temp\cssChecking2.rtf" style=mycss_style;
ods pdf file="c:\temp\cssChecking3.pdf" startpage=never style=mycss_style;
title "Proc PRINT title -- this should be green";
footnote "This should be purple";
proc print data=sashelp.class(obs=5);
title2 'font defined courier new in import css';
run;
ods _all_ close;
I started with the PEARL style because it was originally written for compatibility with the PDF destination, whereas the NORMAL style was not originally written for PDF. NORMAL was originally written for EG and Web Report Studio -- neither of which were PDF-based destinations.
I also only tested with PROC PRINT because my goal was to show that the order of resolution for the class selectors with the same name, either worked or didn't work. The results from using mycss_style are shown here in Acrobat Reader:
As you can see, since Pearl was imported first and the extrastyle.css was imported second, the colors from extrastyle.css were used for the header and title and Courier was used for the data cell and header fonts, but the color from Pearl.css was used for the footnote. So this shows that both CSS files were imported and the class selectors were resolved with the second set of selectors "overriding" the first set of selectors.
Then I tested the "different" style template, the one that imported the sheets in a different order. The code to test the different style template was:
ods _all_ close;
ods html file="c:\temp\cssChecking4.html" style=mycss_diff;
ods rtf file="c:\temp\cssChecking5.rtf" style=mycss_diff;
ods pdf file="c:\temp\cssChecking6.pdf" startpage=never style=mycss_diff;
title "Proc PRINT title pearl.css imported second -- will this be green or not";
footnote "This should be purple";
proc print data=sashelp.class(obs=5);
title2 'font was courier new in import css file what will it be?';
run;
ods _all_ close;
and these results were:
Since Pearl.css was imported second, all the Pearl settings overrode what was in the first extrastyle.css sheet. So the resolution works as expected, when there are same named class selectors.
When I swap out the Pearl.CSS for NORMAL.CSS, I see the same results with this new code:
filename ncss 'C:\Program Files\SASHome\SASEnterpriseGuide\7.1\Styles\normal.css';
filename css 'c:\temp\extrastyle.css';
proc template;
define style mynorm_style;
import ncss; /* import pearl.css first */
import css; /* then import extrastyle.css */
end;
run;
ods _all_ close;
ods html file="c:\temp\cssChecking1n.html" style=mynorm_style;
ods rtf file="c:\temp\cssChecking2n.rtf" style=mynorm_style;
ods pdf file="c:\temp\cssChecking3n.pdf" startpage=never style=mynorm_style;
title "Proc PRINT title -- this should be green";
footnote "This will be default for Normal style";
proc print data=sashelp.class(obs=5);
title2 'font defined courier new in import css';
run;
ods _all_ close;
Then I observe the same behavior as with the Pearl test. If Normal.CSS comes in first in the IMPORT, then the EXTRASTYLE.CSS changes the same named class selectors:
so this shows me that the new CSS file is being used.
You had some specific points that you noted:
1) Yes, when I run your example code, I do see that the list has an outline. I am guessing that has something to do with the fact that all tables with ODS do have a table outside "frame" or border. Usually in PROC REPORT, PROC PRINT or PROC TABULATE, you have to specify FRAME=VOID to get rid of the frame for a TABLE. What I do observe is that if I take the whole issue of CSS out of the CSS picture and I just I use PROC ODSTEXT with style Pearl vs style Normal, is that the table output from Pearl does NOT have a border/outline, but that the table output from Normal has a border -- so you might have to work with Tech Support to find out what has to change in the Normal style to make no outline.
ods pdf file='c:\temp\test_text_pearl.pdf' style=pearl;
title "Report Header no border on output";
title2 'A List';
proc odstext;
list;
item "Item 1" ;
item "Item 2" ;
item "Item 3" ;
end;
end;
run;
ods _all_ close;
ods pdf file='c:\temp\test_text_normal.pdf' style=normal;
title "Report Header does have border on output";
title2 'A List';
proc odstext;
list;
item "Item 1" ;
item "Item 2" ;
item "Item 3" ;
end;
end;
run;
ods _all_ close;
2) When you say that the grid in the first plot is darker than the second plot, that's not what I observe. There is a grid in the first plot, but no grid in the second plot. If I print or zoom to 100% the lines look the same to me.
3) You say that you don't understand why the colors change in the second plot. They changed because your Histogram was not a grouped plot. So there is one color used in the style for "ungrouped" data and a different set of colors used for "grouped" data:
If you run code like this, without GROUP=, but instead using BY, then you will get the same colors.
ods pdf file='c:\temp\showby.pdf' style=mynorm_style;
title2 'A Plot - no colour';
proc sgplot data=sashelp.cars;
histogram weight;
xaxis grid display=(noline) label='Weight';
yaxis grid display=(noline);
run;
proc sort data=trtemp;
by _label_;
run;
proc sgplot data= trtemp ( rename=(col1=value _label_=measure));
by measure;
vbar origin/ response=value /* group=measure groupdisplay=cluster*/;
format value percent6.0;
label measure='Measure' value = 'Value';
run;
ods pdf close;
So I think that your original @import method many not work as you envisioned, but the PROC TEMPLATE with the IMPORT statement should do some of what you want, if you can get the CLASS selectors right. I think my test verifies that the PROC TEMPLATE approach with the IMPORT statement will have the selectors resolve in the expected order.
The issue with the line around the PROC ODSTEXT output is probably something you need to investigate with Tech Support. If you want to change the colors used for the ungrouped or grouped data, then you either have to change the style template colors or you have to use syntax in sgplot, such as an attribute map to change the colors.
Sorry for the long post. Hope this helps,
cynthia
Hi Cythia,
Thanks so much for following this through. I have replicated your examples and make the following notes:
Thanks again for your help.
SAS Innovate 2025 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!
Learn how use the CAT functions in SAS to join values from multiple variables into a single value.
Find more tutorials on the SAS Users YouTube channel.
Ready to level-up your skills? Choose your own adventure.