Insert CSS into loaded HTML in UIWebView / WKWebView
Insert CSS into loaded HTML in UIWebView / WKWebView
我能够成功获取 HTML 内容并显示到我的 UIWebView 中。
但想通过添加外部 CSS 文件来自定义内容。我只能更改文本和字体的大小。我尝试了所有可能的解决方案来进行更改,但它不起作用 - 它没有显示任何更改。
下面是我的代码
HTMLNode* body = [parser body];
HTMLNode* mainContentNode = [body findChildWithAttribute:@"id" matchingName:@"main_content" allowPartial:NO];
NSString *pageContent = [NSString stringWithFormat:@"%@%@", cssString, contentHtml];
[webView loadHTMLString:pageContent baseURL:[NSURL URLWithString:@"http://www.example.org"]];
-(void)webViewDidFinishLoad:(UIWebView *)webView1{
int fontSize = 50;
NSString *font = [[NSString alloc] initWithFormat:@"document.getElementsByTagName('body')[0].style.webkitTextSizeAdjust= '%d%%'", fontSize];
NSString *fontString = [[NSString alloc] initWithFormat:@"document.getElementById('body').style.fontFamily=\"helvetica\""];
[webView1 stringByEvaluatingJavaScriptFromString:fontString];
[webView1 stringByEvaluatingJavaScriptFromString:font];
}
请帮我获取我认为的 css 样式表。
你可以这样做:
- (void)webViewDidFinishLoad:(UIWebView *)webView {
NSString *cssString = @"body { font-family: Helvetica; font-size: 50px }"; // 1
NSString *javascriptString = @"var style = document.createElement('style'); style.innerHTML = '%@'; document.head.appendChild(style)"; // 2
NSString *javascriptWithCSSString = [NSString stringWithFormat:javascriptString, cssString]; // 3
[webView stringByEvaluatingJavaScriptFromString:javascriptWithCSSString]; // 4
}
此代码的作用:
// 1 : 定义一个包含所有 CSS 声明的字符串
// 2 : 定义一个 javascript 字符串,它创建一个新的 <style>
HTML DOM 元素并向其中插入 CSS 声明。实际上插入是在下一步完成的,现在只有 %@
占位符。我这样做是为了防止线路变得太长,但是步骤 2 和步骤 3 可以一起完成。
// 3 : 合并2个字符串
// 4 : 在 UIWebView
中执行 javascript
要使其正常工作,您的 HTML 必须有一个 <head></head>
元素。
编辑:
您还可以从本地 css 文件(在本例中名为 "styles.css")加载 css 字符串。只需将步骤 //1 替换为以下内容:
NSString *path = [[NSBundle mainBundle] pathForResource:@"styles" ofType:@"css"];
NSString *cssString = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
作为另一种选择,您可以将 <link>
元素注入 <head>
以加载 CSS 文件:
- (void)webViewDidFinishLoad:(UIWebView *)webView {
NSString *path = [[NSBundle mainBundle] pathForResource:@"styles" ofType:@"css"];
NSString *javascriptString = @"var link = document.createElement('link'); link.href = '%@'; link.rel = 'stylesheet'; document.head.appendChild(link)";
NSString *javascriptWithPathString = [NSString stringWithFormat:javascriptString, path];
[webView stringByEvaluatingJavaScriptFromString:javascriptWithPathString];
}
此解决方案最适合大型 CSS 文件。不幸的是,它不适用于远程 HTML 文件。仅当您想将 CSS 插入已下载到您的应用程序的 HTML 时才可以使用它。
更新:WKWebView / Swift 3.x
当您使用 WKWebView
时,由于 WKWebView
的安全设置,注入 <link>
元素不起作用。
您仍然可以将 css 作为字符串注入。在您的代码 //1
中创建 CSS 字符串或将其放入本地文件 //2
。请注意,对于 WKWebView,您必须在 WKNavigationDelegate
的 webView(_:didFinish:)
方法中进行注入:
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
insertCSSString(into: webView) // 1
// OR
insertContentsOfCSSFile(into: webView) // 2
}
func insertCSSString(into webView: WKWebView) {
let cssString = "body { font-size: 50px; color: #f00 }"
let jsString = "var style = document.createElement('style'); style.innerHTML = '\(cssString)'; document.head.appendChild(style);"
webView.evaluateJavaScript(jsString, completionHandler: nil)
}
func insertContentsOfCSSFile(into webView: WKWebView) {
guard let path = Bundle.main.path(forResource: "styles", ofType: "css") else { return }
let cssString = try! String(contentsOfFile: path).trimmingCharacters(in: .whitespacesAndNewlines)
let jsString = "var style = document.createElement('style'); style.innerHTML = '\(cssString)'; document.head.appendChild(style);"
webView.evaluateJavaScript(jsString, completionHandler: nil)
}
有关更完整的详细信息,请参阅@joern 接受的答案。我添加这个答案是因为我 运行 遇到了一个奇怪的边缘情况。我的特定用例需要使用 class="dialog"
向 div
添加样式。出于某种原因,使用 .dialog
和 div
的样式无法正常工作,但其他类型的样式可以正常工作。最后我使用以下设置 dialog
的宽度
let width = Int(webView.bounds.width)
let script = "document.getElementsByClassName(\"dialog\")[0].style.width = \"\(width)px\""
webView.evaluateJavaScript(script)
由于 UIWebView
在 iOS 12 中被弃用,我将只回答 WKWebView
。
我已经像接受的答案中描述的那样实现了 CSS 加载。问题是有时从没有 CSS 的 HTML 到 CSS 的 HTML 的过渡是可见的。
我认为更好的方法是使用 WKUserScript
像这样注入 CSS:
lazy var webView: WKWebView = {
guard let path = Bundle.main.path(forResource: "style", ofType: "css") else {
return WKWebView()
}
let cssString = try! String(contentsOfFile: path).components(separatedBy: .newlines).joined()
let source = """
var style = document.createElement('style');
style.innerHTML = '\(cssString)';
document.head.appendChild(style);
"""
let userScript = WKUserScript(source: source,
injectionTime: .atDocumentEnd,
forMainFrameOnly: true)
let userContentController = WKUserContentController()
userContentController.addUserScript(userScript)
let configuration = WKWebViewConfiguration()
configuration.userContentController = userContentController
let webView = WKWebView(frame: .zero,
configuration: configuration)
return webView
}()
您可以在 blog post.
中阅读有关此方法的更多信息
与其将 css 与样式标签一起应用,不如将其与 link 标签一起应用:
func insertContentsOfCSSFile2(into webView: WKWebView) {
guard let path = Bundle.main.path(forResource: "resource", ofType: "css") else { return }
let csFile = "var head = document.getElementsByTagName('head')[0];var link = document.createElement('link'); link.rel = 'stylesheet';link.type = 'text/css';link.href = '\(path)';link.media = 'all';head.appendChild(link);"
webView.evaluateJavaScript(csFile) {(result, error) in
if let error = error {
print(error)
}
}
}
我已经测试过了。
它工作正常。
你需要在 apple 样式之前添加这个 header 到 HTML
let fontName = UIFont.systemFont(ofSize: 17.0).fontName
let htmlContent = """
<header>
<meta name='viewport' content='width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no'>
</header>
<style type='text/css'>
img{max-height: 100%; min-height: 100%; height:auto; max-width: 100%; width:auto;margin-bottom:5px;}
p{text-align:left|right|center; line-height: 180%; font-family: '\(fontName)'; font-size: 17px;}
iframe{width:100%; height:250px;}
</style> \(html)
"""
webView.loadHTMLString(htmlContent, baseURL: Bundle.main.bundleURL)
我尝试了 Amer Hukic 的回答。但并没有像现在这样工作。我在 html 头标签之间添加了以下代码。
<link rel="stylesheet" href="style.css">
我能够成功获取 HTML 内容并显示到我的 UIWebView 中。
但想通过添加外部 CSS 文件来自定义内容。我只能更改文本和字体的大小。我尝试了所有可能的解决方案来进行更改,但它不起作用 - 它没有显示任何更改。
下面是我的代码
HTMLNode* body = [parser body];
HTMLNode* mainContentNode = [body findChildWithAttribute:@"id" matchingName:@"main_content" allowPartial:NO];
NSString *pageContent = [NSString stringWithFormat:@"%@%@", cssString, contentHtml];
[webView loadHTMLString:pageContent baseURL:[NSURL URLWithString:@"http://www.example.org"]];
-(void)webViewDidFinishLoad:(UIWebView *)webView1{
int fontSize = 50;
NSString *font = [[NSString alloc] initWithFormat:@"document.getElementsByTagName('body')[0].style.webkitTextSizeAdjust= '%d%%'", fontSize];
NSString *fontString = [[NSString alloc] initWithFormat:@"document.getElementById('body').style.fontFamily=\"helvetica\""];
[webView1 stringByEvaluatingJavaScriptFromString:fontString];
[webView1 stringByEvaluatingJavaScriptFromString:font];
}
请帮我获取我认为的 css 样式表。
你可以这样做:
- (void)webViewDidFinishLoad:(UIWebView *)webView {
NSString *cssString = @"body { font-family: Helvetica; font-size: 50px }"; // 1
NSString *javascriptString = @"var style = document.createElement('style'); style.innerHTML = '%@'; document.head.appendChild(style)"; // 2
NSString *javascriptWithCSSString = [NSString stringWithFormat:javascriptString, cssString]; // 3
[webView stringByEvaluatingJavaScriptFromString:javascriptWithCSSString]; // 4
}
此代码的作用:
// 1 : 定义一个包含所有 CSS 声明的字符串
// 2 : 定义一个 javascript 字符串,它创建一个新的 <style>
HTML DOM 元素并向其中插入 CSS 声明。实际上插入是在下一步完成的,现在只有 %@
占位符。我这样做是为了防止线路变得太长,但是步骤 2 和步骤 3 可以一起完成。
// 3 : 合并2个字符串
// 4 : 在 UIWebView
中执行 javascript要使其正常工作,您的 HTML 必须有一个 <head></head>
元素。
编辑:
您还可以从本地 css 文件(在本例中名为 "styles.css")加载 css 字符串。只需将步骤 //1 替换为以下内容:
NSString *path = [[NSBundle mainBundle] pathForResource:@"styles" ofType:@"css"];
NSString *cssString = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
作为另一种选择,您可以将 <link>
元素注入 <head>
以加载 CSS 文件:
- (void)webViewDidFinishLoad:(UIWebView *)webView {
NSString *path = [[NSBundle mainBundle] pathForResource:@"styles" ofType:@"css"];
NSString *javascriptString = @"var link = document.createElement('link'); link.href = '%@'; link.rel = 'stylesheet'; document.head.appendChild(link)";
NSString *javascriptWithPathString = [NSString stringWithFormat:javascriptString, path];
[webView stringByEvaluatingJavaScriptFromString:javascriptWithPathString];
}
此解决方案最适合大型 CSS 文件。不幸的是,它不适用于远程 HTML 文件。仅当您想将 CSS 插入已下载到您的应用程序的 HTML 时才可以使用它。
更新:WKWebView / Swift 3.x
当您使用 WKWebView
时,由于 WKWebView
的安全设置,注入 <link>
元素不起作用。
您仍然可以将 css 作为字符串注入。在您的代码 //1
中创建 CSS 字符串或将其放入本地文件 //2
。请注意,对于 WKWebView,您必须在 WKNavigationDelegate
的 webView(_:didFinish:)
方法中进行注入:
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
insertCSSString(into: webView) // 1
// OR
insertContentsOfCSSFile(into: webView) // 2
}
func insertCSSString(into webView: WKWebView) {
let cssString = "body { font-size: 50px; color: #f00 }"
let jsString = "var style = document.createElement('style'); style.innerHTML = '\(cssString)'; document.head.appendChild(style);"
webView.evaluateJavaScript(jsString, completionHandler: nil)
}
func insertContentsOfCSSFile(into webView: WKWebView) {
guard let path = Bundle.main.path(forResource: "styles", ofType: "css") else { return }
let cssString = try! String(contentsOfFile: path).trimmingCharacters(in: .whitespacesAndNewlines)
let jsString = "var style = document.createElement('style'); style.innerHTML = '\(cssString)'; document.head.appendChild(style);"
webView.evaluateJavaScript(jsString, completionHandler: nil)
}
有关更完整的详细信息,请参阅@joern 接受的答案。我添加这个答案是因为我 运行 遇到了一个奇怪的边缘情况。我的特定用例需要使用 class="dialog"
向 div
添加样式。出于某种原因,使用 .dialog
和 div
的样式无法正常工作,但其他类型的样式可以正常工作。最后我使用以下设置 dialog
let width = Int(webView.bounds.width)
let script = "document.getElementsByClassName(\"dialog\")[0].style.width = \"\(width)px\""
webView.evaluateJavaScript(script)
由于 UIWebView
在 iOS 12 中被弃用,我将只回答 WKWebView
。
我已经像接受的答案中描述的那样实现了 CSS 加载。问题是有时从没有 CSS 的 HTML 到 CSS 的 HTML 的过渡是可见的。
我认为更好的方法是使用 WKUserScript
像这样注入 CSS:
lazy var webView: WKWebView = {
guard let path = Bundle.main.path(forResource: "style", ofType: "css") else {
return WKWebView()
}
let cssString = try! String(contentsOfFile: path).components(separatedBy: .newlines).joined()
let source = """
var style = document.createElement('style');
style.innerHTML = '\(cssString)';
document.head.appendChild(style);
"""
let userScript = WKUserScript(source: source,
injectionTime: .atDocumentEnd,
forMainFrameOnly: true)
let userContentController = WKUserContentController()
userContentController.addUserScript(userScript)
let configuration = WKWebViewConfiguration()
configuration.userContentController = userContentController
let webView = WKWebView(frame: .zero,
configuration: configuration)
return webView
}()
您可以在 blog post.
中阅读有关此方法的更多信息与其将 css 与样式标签一起应用,不如将其与 link 标签一起应用:
func insertContentsOfCSSFile2(into webView: WKWebView) {
guard let path = Bundle.main.path(forResource: "resource", ofType: "css") else { return }
let csFile = "var head = document.getElementsByTagName('head')[0];var link = document.createElement('link'); link.rel = 'stylesheet';link.type = 'text/css';link.href = '\(path)';link.media = 'all';head.appendChild(link);"
webView.evaluateJavaScript(csFile) {(result, error) in
if let error = error {
print(error)
}
}
}
我已经测试过了。 它工作正常。
你需要在 apple 样式之前添加这个 header 到 HTML
let fontName = UIFont.systemFont(ofSize: 17.0).fontName
let htmlContent = """
<header>
<meta name='viewport' content='width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no'>
</header>
<style type='text/css'>
img{max-height: 100%; min-height: 100%; height:auto; max-width: 100%; width:auto;margin-bottom:5px;}
p{text-align:left|right|center; line-height: 180%; font-family: '\(fontName)'; font-size: 17px;}
iframe{width:100%; height:250px;}
</style> \(html)
"""
webView.loadHTMLString(htmlContent, baseURL: Bundle.main.bundleURL)
我尝试了 Amer Hukic 的回答。但并没有像现在这样工作。我在 html 头标签之间添加了以下代码。
<link rel="stylesheet" href="style.css">