ios 将 CSS 插入到 UIWebView / WKWebView 中加载的 HTML 中

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/33123093/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 07:59:01  来源:igfitidea点击:

Insert CSS into loaded HTML in UIWebView / WKWebView

iosobjective-cuiwebviewwkwebview

提问by cole

I am successfully able to get HTML content and display into my UIWebView.

我能够成功获取 HTML 内容并显示到我的 UIWebView 中。

But want to customize the content by adding an external CSS file. I can only change the size of text and font. I tried every possible solution to make changes but it does not work - it shows no changes.

但是想通过添加外部 CSS 文件来自定义内容。我只能更改文本和字体的大小。我尝试了所有可能的解决方案来进行更改,但它不起作用 - 它没有显示任何更改。

Below is my code

下面是我的代码

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];
}

Please help me get the css stylesheet in my view.

请帮助我在我的视图中获取 css 样式表。

回答by joern

You can do it like this:

你可以这样做:

- (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
}

What this code does:

这段代码的作用:

// 1 : Define a string that contains all the CSS declarations

// 1 : 定义一个包含所有 CSS 声明的字符串

// 2 : Define a javascript string that creates a new <style>HTML DOM element and inserts the CSS declarations into it. Actually the inserting is done in the next step, right now there is only the %@placeholder. I did this to prevent the line from becoming too long, but step 2 and 3 could be done together.

// 2 : 定义一个 javascript 字符串,用于创建一个新的<style>HTML DOM 元素并将 CSS 声明插入其中。实际上插入是在下一步中完成的,现在只有%@占位符。我这样做是为了防止线路变得太长,但第 2 步和第 3 步可以一起完成。

// 3 : Combine the 2 strings

// 3 : 合并两个字符串

// 4 : Execute the javascript in the UIWebView

// 4 : 在 UIWebView 中执行 javascript

For this to work, your HTML has to have a <head></head>element.

为此,您的 HTML 必须有一个<head></head>元素。

EDIT:

编辑:

You can also load the css string from a local css file (named "styles.css" in this case). Just replace step //1 with the following:

您还可以从本地 css 文件(在本例中名为“styles.css”)加载 css 字符串。只需将步骤 //1 替换为以下内容:

NSString *path = [[NSBundle mainBundle] pathForResource:@"styles" ofType:@"css"];
NSString *cssString = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];

As another option you can just inject a <link>element to the <head>that loads the CSS file:

作为另一种选择,您可以将一个<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];
}

This solution works best for large CSS files. Unfortunately it does not work with remote HTML files. You can only use this when you want to insert CSS into HTML that you have downloaded to your app.

此解决方案最适合大型 CSS 文件。不幸的是,它不适用于远程 HTML 文件。仅当您想将 CSS 插入已下载到应用程序的 HTML 中时,才能使用此功能。

UPDATE: WKWebView / Swift 3.x

更新:WKWebView / Swift 3.x

When you are working with a WKWebViewinjecting a <link>element does not work because of WKWebView's security settings.

当您使用WKWebView注入<link>元素时,由于WKWebView的安全设置而不起作用。

You can still inject the css as a string. Either create the CSS string in your code //1or put it in a local file //2. Just be aware that with WKWebView you have to do the injection in WKNavigationDelegate's webView(_:didFinish:)method:

您仍然可以将 css 作为字符串注入。在您的代码中创建 CSS 字符串//1或将其放在本地文件中//2。请注意,使用 WKWebView 您必须在WKNavigationDelegate'swebView(_: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)
}

回答by Amer Hukic

Since UIWebViewis deprecated in iOS 12, I'll only answer for WKWebView. I've implemented CSS loading like it was described in the accepted answer. The problem was that sometimes the transition from HTML with no CSS applied to HTML with CSS was visible.
I think a better approach is to use the WKUserScriptto inject the CSS like this:

由于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
}()

You can read more about this approach in this blog post.

您可以在此博客文章中阅读有关此方法的更多信息

回答by VIJAY SINGH RAGHAV

Instead of applying css with style tag it's better to apply it with the link tag:

与其将 css 与 style 标签一起应用,不如将其与 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)
        }
    }
}

I have tested it. it is working fine.

我已经测试过了。它工作正常。

回答by Chea Sambath

You need to add this header before apple style to HTML

您需要在苹果样式之前将此标头添加到 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)

回答by SuperGuyAbe

See @joern's accepted answer for more complete details. I'm adding this answer because I ran into a weird edge case. My particular use case needed to add styling to a divwith a class="dialog". For some reason styling using .dialogand divweren't working though other types of styling were working. In the end I used the following to set the width of the dialog

有关更完整的详细信息,请参阅@joern 接受的答案。我添加这个答案是因为我遇到了一个奇怪的边缘情况。我的具体使用情况下需要的造型添加到divclass="dialog"。出于某种原因.dialogdiv虽然其他类型的样式正在工作,但使用和样式却不起作用。最后我使用以下来设置宽度dialog

let width = Int(webView.bounds.width)
let script = "document.getElementsByClassName(\"dialog\")[0].style.width = \"\(width)px\""
webView.evaluateJavaScript(script)