Вставьте CSS в загруженный HTML в 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 на мой взгляд.

Ответ 1

Вы можете сделать это следующим образом:

- (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, которая создает новый элемент HTML DOM <style> и вставляет в него объявления CSS. Фактически вставка выполняется на следующем шаге, прямо сейчас есть только %@ placeholder. Я сделал это, чтобы линия не стала слишком длинной, но шаги 2 и 3 можно было сделать вместе.

//3: Объедините 2 строки

//4: Выполнить javascript в UIWebView

Чтобы это работало, ваш HTML должен иметь элемент <head></head>.

РЕДАКТИРОВАТЬ:

Вы также можете загрузить строку css из локального файла css (с именем "styles.css" в этом случае). Просто замените step//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 элемент <link> не работает из-за WKWebView безопасности WKWebView.

Вы можете добавить css в строку. Либо создайте строку CSS в коде //1 либо поместите ее в локальный файл //2. Просто имейте в виду, что с WKWebView вам нужно сделать инъекцию в WKNavigationDelegate webView(_:didFinish:) method:

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

Ответ 2

Поскольку UIWebView устарела в iOS 12, я отвечу только за WKWebView. Я реализовал загрузку CSS, как это было описано в принятом ответе. Проблема заключалась в том, что иногда переход от HTML без CSS к HTML с CSS был видимым.
Я думаю, что лучший подход - использовать 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
}()

Подробнее об этом подходе можно прочитать в этом блоге.

Ответ 3

Вместо применения 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)
        }
    }
}

Я проверил это. это работает нормально.

Ответ 4

Для получения более подробной информации см. @Joern. Я добавляю этот ответ, потому что я столкнулся с странным случаем. Мой конкретный пример использования должен был добавить стиль в div с помощью class="dialog". По какой-то причине стиль с использованием .dialog и div не работал, хотя работали другие типы стилей. В конце я использовал следующее, чтобы установить ширину dialog

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

Ответ 5

Вы должны добавить этот заголовок перед стилем Apple в 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)