iframe CSS Override for New Twitter Widget

2020-03-01 07:24发布

问题:

I'm trying to customise the new Twitter widget, but having some problems with the CSS and can't seem to override theirs on this new one. I've tried searching for solutions but can't find any that match.

Here's my page with the widget in the right-nav and the tweaked CSS for the .timeline class:

.timeline {
margin-bottom:0;
border:0 !important;
border-radius:0 !important;
-webkit-border-radius:0;
-moz-border-radius:0;
}

html:

<div class="bg">
<h3 class="twitter">Twitter News</h3>
<div id="twitter">
<a class="twitter-timeline" href="https://twitter.com/" data-widget-id="268336500536647680">Tweets by </a>
<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src="//platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script>
</div></div>

I've started using !important declarations and tried the main #twitter id to override, but neither works.

Any ideas much appreciated.

**I apparently need to edit the iframe somehow, but not sure how - if anyone has a clearer idea how I can do that with my code (as opposed to a tutorial) that would be great. I also need to change the iframe width..

回答1:

I managed to do this with javascript (I use jQuery in my application!). You have to apply the styles after the iframe load (I did not find a valid "loaded" event, so I use a polling strategy).

// Customize twitter feed
var hideTwitterAttempts = 0;
function hideTwitterBoxElements() {
    setTimeout( function() {
        if ( $('[id*=twitter]').length ) {
        $('[id*=twitter]').each( function(){
            if ( $(this).width() == 220 ) {
                $(this).width( 198 ); //override min-width of 220px
            }
            var ibody = $(this).contents().find( 'body' );
            ibody.width( $(this).width() + 20 ); //remove scrollbar by adding width

            if ( ibody.find( '.timeline .stream .h-feed li.tweet' ).length ) {
            ibody.find( '.timeline' ).css( 'border', 0 );
            ibody.find( '.timeline .stream' ).css( 'overflow-x', 'hidden' );
            ibody.find( '.timeline .stream' ).css( 'overflow-y', 'scroll' );
            ibody.find( '.timeline-header').hide();
            ibody.find( '.timeline-footer').hide();
            }
            else {
                $(this).hide();
            }
        });
        }
        hideTwitterAttempts++;
        if ( hideTwitterAttempts < 3 ) {
            hideTwitterBoxElements();
        }
    }, 1500);
}

// somewhere in your code after html page load
hideTwitterBoxElements();


回答2:

This is without jQuery for anyone interested.

UPDATED with much better solution that doesn't rely on polling and therefore doesn't have a flash of unstyled layout on occasion:

twttr.events.bind('rendered',function(){
  [].slice.call(document.querySelectorAll('iframe.twitter-timeline')).forEach(function(e,i,a){
    var fE = e.contentDocument.getElementsByClassName('timeline-footer');
    if(fE.length){
      fE[0].style.backgroundColor='transparent';
    }
  });
});

old version:

// Customize twitter feed                                                                              
var hideTwitterAttempts = 0;                                                                           
function hideTwitterBoxElements() {                                                                    
    setTimeout( function() {                                                                           
        var list = document.getElementsByTagName('iframe');                                            
        if (list.length ) {                                                                            
            Array.prototype.forEach.call(                                                              
                list,                                                                                  
                function(element){                                                                     
                    var footerE = element.contentDocument.getElementsByClassName('timeline-footer')[0];
                    footerE.style.backgroundColor="transparent";                                       
                });                                                                                    
        }                                                                                              
        hideTwitterAttempts++;                                                                         
        if ( hideTwitterAttempts < 3 ) {                                                               
            hideTwitterBoxElements();                                                                  
        }                                                                                              
    }, 1500);                                                                                          
}                                                                                                      
hideTwitterBoxElements();                                                                              


回答3:

I adapted the code from @Sebastiaan Ordelman and added some comments (referring to values from old API). This was my attempt to match the old API in a short amount of time. Place this code after your new copy and paste code from the new twitter widget.

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
<script>
var hideTwitterAttempts = 0;
function hideTwitterBoxElements() {
    setTimeout( function() {
        if ( $('[id*=twitter]').length ) {
        $('[id*=twitter]').each( function(){
            var ibody = $(this).contents().find( 'body' );

            if ( ibody.find( '.timeline .stream .h-feed li.tweet' ).length ) {
            ibody.find( '.customisable-border' ).css( 'border', 0 );
            ibody.find( '.timeline' ).css( 'background-color', '#004A7B' ); //theme: shell: background:
            ibody.find( 'ol.h-feed' ).css( 'background-color', '#0575A1' ); //theme: tweets: background:
            ibody.find( 'ol.h-feed' ).css( 'border-radius', '5px 5px 5px 5px' );
            ibody.find( 'li.tweet' ).css( 'border-bottom', '1px dotted #FFFFFF' ); //theme: tweets: color:
            ibody.find( 'li.tweet' ).css( 'color', '#FFFFFF' ); //theme: tweets: color:
            ibody.find( '.customisable:link' ).css( 'color', '#07E0EB' ); //theme: tweets: links:
            ibody.find( '.footer' ).css( 'visibility', 'hidden' ); //hide reply, retweet, favorite images
            ibody.find( '.footer' ).css( 'min-height', 0 ); //hide reply, retweet, favorite images
            ibody.find( '.footer' ).css( 'height', 0 ); //hide reply, retweet, favorite images
            ibody.find( '.avatar' ).css( 'height', 0 ); //hide avatar
            ibody.find( '.avatar' ).css( 'width', 0 ); //hide avatar
            ibody.find( '.p-nickname' ).css( 'font-size', 0 ); //hide @name of tweet
            ibody.find( '.p-nickname' ).css( 'visibility', 'hidden' ); //hide @name of tweet
            ibody.find( '.e-entry-content' ).css( 'margin', '-25px 0px 0px 0px' ); //move tweet up (over @name of tweet)
            ibody.find( '.dt-updated' ).css( 'color', '#07E0EB' ); //theme: tweets: links:
            ibody.find( '.full-name' ).css( 'margin', '0px 0px 0px -35px' ); //move name of tweet to left (over avatar)
            ibody.find( 'h1.summary' ).replaceWith( '<h1 class="summary"><a class="customisable-highlight" title="Tweets from fundSchedule" href="https://twitter.com/fundschedule" style="color: #FFFFFF;">fundSchedule</a></h1>' ); //replace Tweets text at top
            ibody.find( '.p-name' ).css( 'color', '#07E0EB' ); //theme: tweets: links:
            }
            else {
                $(this).hide();
            }
        });
        }
        hideTwitterAttempts++;
        if ( hideTwitterAttempts < 3 ) {
            hideTwitterBoxElements();
        }
    }, 1500);
}

// somewhere in your code after html page load
hideTwitterBoxElements();
</script>

Image of change: http://img837.imageshack.us/img837/1139/btjc.png



回答4:

This doesn't directly answer CSS aspect of the question, but I think it's worth noting for completeness that some of what you want (eg hide borders / header) can be done using the data- attributes passed in the widget:

<a class="twitter-timeline" href="https://twitter.com/twitterapi" 
    data-widget-id="YOUR-WIDGET-ID-HERE" 
    data-theme="dark"
    data-chrome="noheader nofooter noborders noscrollbar transparent"
    data-link-color="#cc0000"
    width="200"
    height="300"
    >Tweets by @twitterapi</a>

https://dev.twitter.com/docs/embedded-timelines#customization

Maybe there's a performance benefit to minimising javascript arm wrestling where possible?



回答5:

They create an iframe, so it is another document.

You cannot style elements in another document, so it is not possible unless twitter provides a hook to embed your own stylesheet in their iframe..

Twitter only allows to style the link color of the widget and pick a light/dark theme.


Alternatively, you can create your own widget by using the twitter API and then you can style it anyway you want..



回答6:

I don't know if it was possible back then when the question was asked, but now it is, check the docs:

<a class="twitter-timeline" data-chrome="nofooter" ....">Tweets</a>


回答7:

It may be better to use twitters eventing structure.

as per https://dev.twitter.com/web/javascript/loading

<script>window.twttr = (function (d, s, id) {
  var t, js, fjs = d.getElementsByTagName(s)[0];
  if (d.getElementById(id)) return;
  js = d.createElement(s); js.id = id;
  js.src= "https://platform.twitter.com/widgets.js";
  fjs.parentNode.insertBefore(js, fjs);
  return window.twttr || (t = { _e: [], ready: function (f) { t._e.push(f) } });
}(document, "script", "twitter-wjs"));</script>

and per https://dev.twitter.com/web/javascript/events your event and hookup would look something like this (keep in mind this example uses jquery you can opt for a javascript only approach)

twttr.ready( function(twttr){
    twttr.events.bind("rendered", function(tw_event){
    var tw_iframe = ev.target;

    //the following is custom jquery code to do various 
    //css overrides based on selectors
    var twitterbody = $(tw_iframe).contents().find( 'body' );
       twitterbody.find(".avatar").hide();
       twitterbody.find("li.tweet").css({padding: "2px"});
    });
});


回答8:

As said above, you can't change CSS in a different origin iframe, here is some info:

How to apply CSS to iframe?

http://www.jquery4u.com/dom-modification/jquery-change-css-iframe-content/