How to prevent a TWebBrowser from displaying a document's background #58
Recently I got asked how to prevent an HTML document's background from being displayed in a TWebBrowser control. On investigation I found that there are four likely places where a HTML or XHTML document sets the background are:
-
From an external style sheet imported via the
<link>
tag or via an @import statement in a<style>
tag. -
From CSS code embedded in a
<style>
tag. -
From a style attribute in the
<body>
tag. -
From various deprecated attributes of the
<body>
tag.
To remove the background we need to scan a loaded HTML document, find the attributes and objects that define the background and reset their values. The styleSheets collection of the web browser's document object gives access to both the external and embedded style sheets. So that deals with cases 1 and 2 above. To deal with case 3 we need to find the document's body tag and access its style property. This can be found via the body tag's IHTMLElement interface. Finally, for case 4 we need to find the relevant attributes of the body tag. They are exposed by the background and bgColor properties of IHTMLBodyElement.
Starting with cases 1 and 2, the following code does what we want:
procedure HandleStyleSheets(const Document: IDispatch); var Doc: IHTMLDocument2; // document object StyleSheets: IHTMLStyleSheetsCollection; // document's style sheets SheetIdx: Integer; // loops thru style sheets OVSheetIdx: OleVariant; // index of a style sheet StyleSheet: IHTMLStyleSheet; // reference to a style sheet OVStyleSheet: OleVariant; // variant ref to style sheet RuleIdx: Integer; // loops thru style sheet rules Style: IHTMLRuleStyle; // ref to rule's style begin // Get IHTMLDocument2 interface of document if not Supports(Document, IHTMLDocument2, Doc) then Exit; // Loop through all style sheets StyleSheets := Doc.styleSheets; for SheetIdx := 0 to Pred(StyleSheets.length) do begin OVSheetIdx := SheetIdx; // sheet index as variant required for next call // Get reference to style sheet (comes as variant which we convert to // interface reference) OVStyleSheet := StyleSheets.item(OVSheetIdx); if VarSupports(OVStyleSheet, IHTMLStyleSheet, StyleSheet) then begin // Loop through all rules within style a sheet for RuleIdx := 0 to Pred(StyleSheet.rules.length) do begin // Get style from a rule and reset required attributes. // Note: style is IHTMLRuleStyle, not IHTMLStyle, although many // attributes are shared between these interfaces Style := StyleSheet.rules.item(RuleIdx).style; Style.backgroundImage := ''; // removes any background image Style.backgroundColor := ''; // resets background colour to default end; end; end; end;
The comments hopefully explain but briefly, we loop through all the style sheets, and all the rules within each style sheet. We use the style property associated with each rule to access and reset the required style properties.
The next routine deals with case 3, the style attribute of the body tag. We simply grab the style property of the body tag's IHTMLElement interface.
procedure HandleBodyStyleAttrs(const Document: IDispatch); var Doc: IHTMLDocument2; // document object BodyElem: IHTMLElement; // reference to body element Style: IHTMLStyle; // reference to body element's style attribute begin // Get document's IHTMLDocument2 interface if not Supports(Document, IHTMLDocument2, Doc) then Exit; // Get body tag's IHTMLElement interface if not Supports(Doc.body, IHTMLElement, BodyElem) then Exit; // Get style attribute of body element and reset required attributes Style := BodyElem.style; Style.backgroundImage := ''; // removes any background image Style.backgroundColor := ''; // resets background colour to default end;
The last routine deals with case 4, the deprecated attributes of the body tag. This time instead of the IHTMLElement interface of the body tag we use its IHTMLBodyElement interface to access the relevant attributes.
procedure HandleBodyAttrs(const Document: IDispatch); var Doc: IHTMLDocument2; // document object BodyElem: IHTMLBodyElement; // reference to body element begin // Get document's IHTMLDocument2 interface if not Supports(Document, IHTMLDocument2, Doc) then Exit; // Get body tag's IHTMLBodyElement interface if not Supports(Doc.body, IHTMLBodyElement, BodyElem) then Exit; // Reset required deprecated attributes of body tag BodyElem.background := ''; // removes any background image BodyElem.bgColor := ''; // resets background colour to default end;
To use these routines you should load a new document into the web browser
control, wait for the document to load then call each of the routines. Any
background should hopefully be removed. Here's some example code that loads
a HTML document named Test.html
into a TWebBrowser
named WebBrowser1:
begin WebBrowser1.Navigate('Test.html'); while WebBrowser1.ReadyState <> READYSTATE_COMPLETE do Application.ProcessMessages; HandleStyleSheets(WebBrowser1.Document); HandleBodyStyleAttrs(WebBrowser1.Document); HandleBodyAttrs(WebBrowser1.Document); end;
Demo code
A ready made project containing this demo code is available. View the project.
This demo loads a selected website into a browser control and then uses the routines presented in this tip to remove any background colours.
Start a new Delphi VCL application. Drop TWebBrowser,
TEdit and TButton controls onto the form.
Create an OnClick event handler for the button. Name the
form "Form1" and save the unit as Unit1.pas
.
Now code Unit1 as follows:
unit Unit1; interface uses SHDocVw, StdCtrls, Classes, Controls, OleCtrls, Forms; type TForm1 = class(TForm) WebBrowser1: TWebBrowser; Edit1: TEdit; Button1: TButton; procedure Button1Click(Sender: TObject); end; var Form1: TForm1; implementation uses SysUtils, Variants, Windows, MSHTML; {$R *.dfm} procedure HandleStyleSheets(const Document: IDispatch); var Doc: IHTMLDocument2; StyleSheets: IHTMLStyleSheetsCollection; SheetIdx: Integer; OVSheetIdx: OleVariant; StyleSheet: IHTMLStyleSheet; OVStyleSheet: OleVariant; RuleIdx: Integer; Style: IHTMLRuleStyle; begin if not Supports(Document, IHTMLDocument2, Doc) then Exit; StyleSheets := Doc.styleSheets; for SheetIdx := 0 to Pred(StyleSheets.length) do begin OVSheetIdx := SheetIdx; OVStyleSheet := StyleSheets.item(OVSheetIdx); if VarSupports(OVStyleSheet, IHTMLStyleSheet, StyleSheet) then begin for RuleIdx := 0 to Pred(StyleSheet.rules.length) do begin Style := StyleSheet.rules.item(RuleIdx).style; Style.backgroundImage := ''; Style.backgroundColor := ''; end; end; end; end; procedure HandleBodyStyleAttrs(const Document: IDispatch); var Doc: IHTMLDocument2; BodyElem: IHTMLElement; Style: IHTMLStyle; begin if not Supports(Document, IHTMLDocument2, Doc) then Exit; if not Supports(Doc.body, IHTMLElement, BodyElem) then Exit; Style := BodyElem.style; Style.backgroundImage := ''; Style.backgroundColor := ''; end; procedure HandleBodyAttrs(const Document: IDispatch); var Doc: IHTMLDocument2; BodyElem: IHTMLBodyElement; begin if not Supports(Document, IHTMLDocument2, Doc) then Exit; if not Supports(Doc.body, IHTMLBodyElement, BodyElem) then Exit; BodyElem.background := ''; BodyElem.bgColor := ''; end; procedure TForm1.Button1Click(Sender: TObject); // from https://delphidabbler.com/tips/72 procedure Pause(ADelay: Cardinal); var StartTC: Cardinal; begin StartTC := GetTickCount; repeat Application.ProcessMessages; until Int64(GetTickCount) - Int64(StartTC) >= ADelay; end; begin WebBrowser1.Navigate(Edit1.Text); while WebBrowser1.ReadyState <> READYSTATE_COMPLETE do Pause(5); HandleStyleSheets(WebBrowser1.Document); HandleBodyStyleAttrs(WebBrowser1.Document); HandleBodyAttrs(WebBrowser1.Document); end; end.
Run the application. Enter a web page address in the edit box and click the button. The web page will be displayed in the browser control. When the web page has finished loading the background colours should be removed. Note there may be quite a delay before this happens.
All that happens in the button click event is that the web page is loaded and a loop is entered waiting for the web document to finish loading. Then the three routines presented in this tip are called to try to remove the background. Once this is done the browser re-displays the web page.
Going further
In addition to the background you may also want to reset the body text colour to the browser default. To do this set the color properties of IHTMLRuleStyle and IHTMLStyle and the text property of IHTMLBodyElement to the empty string.
You can also use these techniques to force a required background, colours, margins etc.
Author: | Peter Johnson |
---|---|
Contributor: | Peter Johnson |
Added: | 2007/10/29 |
Last updated: | 2010/03/16 |