function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
t.ishibuchit.ishibuchi 

本番環境にアップロードしたCSSファイルがブラウザで正常に読み込まれない

大変お世話になっております。t.ishibuchiと申します。

本番環境にアップロードしたCSSファイルがブラウザで正常に読み込まれない、という事象が発生しました。

その原因・対策について、ご助言頂けましたら幸いでございます。


**************************************
▼事象
VFページから静的リソース上のCSSファイルを読み込むようにしております。
また、Force.com サイトにてそのページを公開しています。

先日(2014/9/2)そのCSSを編集し、リリースを行った際に、
本番環境にアップロードされた該当のCSSファイルがブラウザで読み込まれておらず、
それが原因でSandbox環境と比べて画面レイアウトが崩れてしまうという事象が発生しました。

なお、アクセスしたデバイスによってCSSを切り替えるように、
VFには以下のように実装しています。

--VFページ-------------------------------------------------------------------

<script type="text/javascript">
    <!-- css切り替え -->
    (function(){
        var device = navigator.userAgent;
        if((device.indexOf('iPhone') > 0 && device.indexOf('iPad') == -1) || device.indexOf('iPod') > 0 || device.indexOf('Android') > 0){
            document.write('<link class="user" href="/resource/css_sp" rel="stylesheet" type="text/css" />');
        }
        else{
            document.write('<link class="user" href="/resource/css_pc" rel="stylesheet" type="text/css" />');
        }
    })();
</script>

----------------------------------------------------------------------------


**************************************
▼対応
CSSファイル名称を変更して新規に作成し(中身は同一)、該当の画面でそのファイルを読み込むように修正をしたところ、思惑通りの画面レイアウトが正常に表示されました。

なお、上記VF内記載のスクリプトは、以下のように修正し、新規のCSSを呼び出すようにしました。
(CSSファイルは、「css_pc.css」をコピーし、名称を「css_pc_20140903.css」に変更してアップロードしています。「css_sp.css」も同様)

--VFページ-------------------------------------------------------------------

document.write('<link class="user" href="/resource/css_pc" rel="stylesheet" type="text/css" />');

↓修正↓

document.write('<link class="user" href="/resource/css_pc_20140903" rel="stylesheet" type="text/css" />');

----------------------------------------------------------------------------


**************************************
▼望ましい動作
上記対応を行わなくとも(同名のCSSファイルを更新してリリースしただけで)、本番環境にリリースした最新のCSSが読み込まれることが望ましい動作です。


**************************************


あくまで推測ですが、キャッシュサーバ上にあった、古いCSSが読み込まれていた為、レイアウト崩れが発生していたのでは?と思いました。

因みにですが、Sandbox環境のCSSを更新した場合は即座にそのCSSが読み込まれますし、
本番環境においても今回のリリース時に初めて、最新のリリースしたCSSが読み込まれないという事象が発生しました。

もし本事象の原因およびその対策につきまして、お分かりになる方いらっしゃいましたらご教示頂けますでしょうか。
Jon SnowJon Snow
t.ishibuchiさん

キャッシュの可能性があるなら、apex:pageのタグにcache="false"を指定したらいかがでしょうか。
t.ishibuchit.ishibuchi

Jon Snow さん

コメントありがとうございます。対策案の1つとして検討させて頂きます。
取り急ぎ御礼まで。


なお補足ですが、
上記事象は、ブラウザキャッシュを削除の上で確認をしておりましたが、やはり最新のCSSが読み込まれませんでした。
また、静的リソースのキャッシュコントロールは、「公開」に設定しております。

Jon SnowJon Snow
t.ishibuchiさん

CSSファイルインポートの書き方は若干気になります。
下記の2つ方法を試したらいかがでしょうか。

▅方法1.apex:stylesheetタグを使用する
「VFページ」
document.write('<link class="user" href="/resource/css_pc" rel="stylesheet" type="text/css" />');
→document.write('<apex:stylesheet value="{!$Resource.css_pc}"/>');

▅方法2.APEXからファイルパスをゲットする
「APEX」
//メンバー変数
cssResourcePath = getResourcePath('css_pc'); 

private String getResourcePath(String resourceName){
  // Fetching the resource
        List<StaticResource> resourceList= [SELECT Name, NamespacePrefix, SystemModStamp FROM StaticResource WHERE Name = :resourceName];

        // Checking if the result is returned or not
        if(resourceList.size() == 1){

         // Getting namespace
         String namespace = resourceList[0].NamespacePrefix;
         // Resource URL
         return '/resource/' + resourceList[0].SystemModStamp.getTime() + '/' + (namespace != null && namespace != '' ? namespace + '__' : '') + resourceName;
        }
        return '';
}

「VFページ」
document.write('<link class="user" href="{!cssResourcePath}" rel="stylesheet" type="text/css" />');
t.ishibuchit.ishibuchi

Jon Snow さん

ご丁寧に誠にありがとうございます!検証させて頂きます。

取り急ぎ、御礼まで。

t.ishibuchit.ishibuchi
Jon Snow さん

ご教示いただきました方法1、方法2ともに試してみました。
結論から言うと方法2のほうを採用させていただきました。

方法1では、CSSを読み込むタイミングが今までと変わってしまい、
スタイルが崩れてしまったため使用できませんでした。

方法2では、今までと変わらずに期待通りに本番環境にリリースしたCSSが反映されることを確認できました。


しかし、他に問題が出てきてしまいました。
現象としましては、
先述いたしましたようにアクセスしたデバイスによってCSSを切り替えようとしている為、今までのようにスクリプトで読み込むCSSを返れるようにactionFunctionを使用して、
スクリプトからコントローラ内で定義したメソッドを実行し参照したいCSSのパスを取得するように修正したのですが、画面側でパスが取得できずスタイルが崩れてしまいました。

スクリプトでのメソッド実行が問題と思い、いろいろと試してみたのですが修正できずにおります。

#スクリプトで読み込むCSSのパスを取得するメソッドを実行しているので、サーバ側ではパスを保持しているが、画面側にはパスのデータを保持していない。

#再描画等も、試してみたが画面が完全に表示されていないので意味がない。

以下、対応方法

==VF===

<apex:form id="URLform">
    <apex:actionFunction name="spcreate" action="{!createSpPath}" reRender="URLHidden"/>
    <apex:actionFunction name="pccreate" action="{!createPcPath}" reRender="URLHidden"/>
</apex:form>


<script type="text/javascript">
    <!-- css切り替え -->
    (function(){
        var device = navigator.userAgent;
        if((device.indexOf('iPhone') > 0 && device.indexOf('iPad') == -1) || device.indexOf('iPod') > 0 || device.indexOf('Android') > 0){
            spcreate();
        }
        else{
            pccreate();
        }

    })();
</script>

==APEX===

public pagereference createSpPath(){
    //ファイルパス作成実行
    cssResourcePath = getResourcePath('css_sp_test');

    return null;
}

//apex:actionFunctionからの実行(パラメータの受け取り)
public pagereference createPcPath(){
    //ファイルパス作成実行
    cssResourcePath = getResourcePath('css_pc_test');
   
    return null;
}

public String getResourcePath(String resourceName){
    // Fetching the resource
    List<StaticResource> resourceList= [SELECT Name, NamespacePrefix, SystemModStamp FROM StaticResource WHERE Name = :resourceName];

    // Checking if the result is returned or not
    if(resourceList.size() == 1){

        // Getting namespace
        String namespace = resourceList[0].NamespacePrefix;
        // Resource URL
        return '/resource/' + resourceList[0].SystemModStamp.getTime() + '/' + (namespace != null && namespace != '' ? namespace + '__' : '') + resourceName;
    }
    return 'error';
}


==============
度々、誠に恐れ入りますが、何かアドバイス頂ければ幸いでございます。
Jon SnowJon Snow
t.ishibuchiさん

Javascriptからapex:actionFunctionを呼び出して、Apexが動いても画面上のJavascriptが再実行されないので、
デバイスによって、PCかスマートフォン向けのCSSファイルを読込たいであれば、
Webserviceを利用して実装が可能だと気がします。


以下、実装方向

1.Javascriptでデバイスを判定し、ApexのWebserviceにパラメータを投げる
2.ApexのWebserviceから指定したデバイスのCss静的ファイルパスをリターンする
3.Javascriptで取得したパスで画面にスタイルシートインポートのタグを出力する(Document.write..)

Webserviceの参照:
https://www.salesforce.com/us/developer/docs/apexcode/Content/apex_and_ajax.htm


t.ishibuchit.ishibuchi
Jon Snowさん

ご教示ありがとうございました。

ご教示いただいた方法とは別の方法で思い通りの動作をしました。
結論から言うと私の認識間違いでした。パスの指定を"/resource/css_pc"と指定していたのが原因だったようで、下記のような記述にするとうまくいきました。

document.write('<link class="user" href="/resource/css_pc" rel="stylesheet" type="text/css" />');
→document.write('<link class="user" href="{!$Resource.css_pc}" rel="stylesheet" type="text/css" />');

ご教示いただきました。webserviceを使用した方法を試してみましたが、ブラウザ上で、表示させた際に500"Internal Serveice Error"が表示されてしまい、ファイルパスにnullが指定されてしまうため、CSSが読み込めませんでした。

showHeader="fales"に設定していたため正常に動作していなかったようで、回避策として"var __sfdcSessionId = '{!GETSESSIONID()}';"を設定してみましたが、うまくいきませんでした。
→showHeader="true"に設定するとCSSファイルを読み込むことはできました。

ご対応ありがとうございました。